Java Web 之 Servlet

本文包括:

  1. Servlet简介

  2. 关于Servlet的一些类

  1. Servlet生命周期
  1. ServletConfig获得初始化参数
  1. web引用对象——ServletContext(上下文)
  1. 缺省Servlet

1、Servlet简介

  • Servlet技术基于Request-Response编程模型 ---- HTTP协议也是基于此模型(请求-响应模型)

  • Sun公司在其API中提供了一个Servlet接口,用户若想开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下两个步骤:

    • 编写一个Java类,实现Servlet接口

    • 把开发好的Java类部署到web服务器中

  • 快速入门,用Servlet向浏览器输出“hello servlet”

    • 使用MyEclipse创建web project

    • 通过向导创建Servlet继承HttpServlet,假设新建的Java文件为:cn.itcast.servlet.HelloServlet.java

    • 在web.xml配置Servlet程序,配置Servlet虚拟路径(用户通过这个虚拟路径访问Servlet程序)

       <!-- 为 HelloServlet 配置 浏览器可以访问虚拟 路径 -->    
    
          <servlet>
              <!-- 为 Servlet程序  命名 -->
              <servlet-name>HelloServlet</servlet-name>
              <!-- Servlet全路径 : 包名.类名 -->
              <servlet-class>cn.itcast.servlet.HelloServlet</servlet-class>
          </servlet>
    
       <servlet-mapping>
    
              <!-- 为Servlet程序 指定 浏览器访问 虚拟路径 -->
              <servlet-name>HelloServlet</servlet-name>
              <!-- 用户 在 浏览器通过/hello 访问Servlet -->
              <url-pattern>/hello</url-pattern>
          </servlet-mapping>
    
    • 覆写(override)doGet或者doPost方法(一般修改为public),在里面撰写代码,进行输出

执行过程

  1. 用户在客户端发起url请求 : http://localhost/day05/hello

    在当前项目下,服务器会找到 web.xml 中URL为hello的servlet-mapping,然后得到servlet-name,再找到servlet-class,即映射 HelloServlet程序

  2. 用户提交请求时,若为get方式提交,则执行HelloServlet的doGet方法;若为post方式提交,则执行HelloServlet的doPost方法

Servlet程序在编写和运行时,需要javaee 类库 (API支持)

  • 在学习javase时,想用List必须要import java.util.List,则需要JDK中jre/lib/rt.jar

  • MyEclipse创建webproject,则会自动导入 javaee5 liberary,其中存在 javaee.jar ,它提供 Servlet 所需要的API支持 (开发环境使Servlet程序正常编译)

  • Serlvet程序运行tomcat环境中,webapps\项目名字\WEB-INF\lib中没有javaee.jar, 其实jar包在tomcat的根目录的lib中,,tomcat/lib/servlet-api.jar 提供了Servlet程序运行所需要的API支持 (运行环境需要的)

手动编写Servlet运行

  1. 在tomcat\webapps 新建 day05test目录 --- 虚拟应用

  2. 在day05test 新建 WEB-INF\classes

  3. 将编写Servlet的java源码文件放入 classes ,在 WEB-INF下配置web.xml

  4. 编译Servlet的 java程序

     javac -classpath E:\apache-tomcat-6.0.14\lib\servlet-api.jar HelloServlet.java
    

    通过 -classpath 参数指定 Servlet所需要的jar包,该jar包位于E:\apache-tomcat-6.0.14\lib\servlet-api.jar

    生成Servlet package结构

     javac -d . -classpath E:\apache-tomcat-6.0.14\lib\servlet-api.jar HelloServlet.java
    

    通过 -d .,可以自动生成package(根据java文件的首行代码:package XX.XX.XX;

2、关于Servlet的一些类

  • Servlet接口

    • 定义了所有Servlet需要实现的方法

    • 它定义了init destory service等方法

    • 为了解决基于请求-响应模型的数据处理(没有涉及与HTTP协议相关的API)

  • GenericServlet抽象类

    • 它是Servlet接口的实现类

    • 它扩展了一些方法

    • 也没有涉及与HTTP协议相关的API

  • HttpServlet抽象类

    • 它继承于GenericServlet

    • 它新增了一些与HTTP协议相关的方法,如doGet,doPost等等

    • HttpServlet在实现Servlet接口时,覆写了service方法,该方法内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,程序员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法

  • HttpServlet比Servlet更为强大,也可以保护Servlet接口不被轻易改动,所以程序员自己创建的Servlet都是继承于HttpServlet,从而间接地实现了Servlet接口。

3、Servlet生命周期

  • 生命周期

    1. 实例化:Servlet 容器创建 Servlet 的实例

    2. 初始化 :该容器调用 init 方法

    3. 请求处理:如果请求 Servlet,则容器调用 service 方法

    4. 服务终止:销毁实例之前调用 destroy 方法

    其中,init方法只有在Servlet第一次被请求加载时被调用一次,当有客户再请求Servlet服务时,web服务器将启动一个新的线程,在该线程中,调用service方法响应客户的请求。

  • 常用方法

    • init(ServletConfig config) 初始化

    • service(ServletRequest req, ServletResponse res) 提供服务方法

    • destroy() 销毁

  • 特征

    1. tomcat服务器启动时,没有创建Servlet对象

    2. 第一次访问时,tomcat构造Servlet对象(可以重写无参构造方法来测试),然后调用init方法,再执行service方法。

    3. 从第二次以后访问 tomcat 不会重新创建Servlet对象,也不会调用init ---- 但每一次访问都会创建一个新的线程,线程中都会调用service方法。

    4. 当服务器重启或正常关闭时 调用destroy方法(正常关闭 shutdown.bat)

    注意:

    • Servlet对象是tomcat创建的,tomcat服务器会在每次调用Servlet的service方法时,为该方法创建HttpServletRequest对象和HttpServletResponse对象。

    • 在JavaEE的API中没有Request和Response实现类 ----- 实现类由Servlet服务器提供,即tomcat、weblogic等服务器提供这两个实现类。

    • service方法 和 HttpServlet doGet/doPost 关系区别? ----- 必须阅读HttpServlet源代码。
      在HttpServlet代码实现中,根据请求方式不同,调用相应doXXX方法:get方式请求 --- doGet ; post方式 --- doPost 。(即service方法的作用是:判断请求方式,再根据请求方式执行HttpServlet的doGet或者doPost方法

一个Servlet可以配置多个url-pattern

  • URL 配置格式 三种:

    1. 完全路径匹配 (以/开始 ) 例如:/hello/init

      • 当前工程没有被正确发布,访问该工程所有静态资源、动态资源 发生404 ----- 工程启动时出错了

      • 查看错误时 分析错误

        • 单一错误 : 从上到下 查看第一行你自己写代码 (有的错误与代码无关,查看错误信息)

        • 复合错误 Caused by ---- 查看最后一个Caused by

    2. 目录匹配 (以/开始) 例如:/*/abc/*

      / 代表网站根目录

      /*表示任何路径都可以匹配到这个Servlet

      /abc/*表示abc目录下的任何路径都可以匹配到这个Servlet

    3. 扩展名 (不能以/开始) 例如:*.do*.action

      典型错误: /*.do

  • 优先级:完全匹配>目录匹配 > 扩展名匹配

相对路径与绝对路径的区别

  • 前提:某Servlet在web.xml中的url-pattern的内容一般为/myServlet,其中,/表示根目录,假设项目名字为MyProject,则该Servlet的URL为:http://localhost:8080/MyProject/myServlet.

  • 在JSP或者HTML页面中的form表单中的action属性需填写Servlet的URL,这里就牵涉到了相对路径与绝对路径的问题。

    • 若采用相对路径

      • 假设该JSP或者HTML页面位于网站根目录,而从“前提”可知Servlet也位于根目录,则直接在action中填写myServlet即可。

      • 假设该JSP或者HTML页面位于网站根目录的aaa文件夹中,则需要在action中填写../myServlet

    • 若采用绝对路径(绝对路径 以/开始,/访问服务器根目录)

      • 不管该JSP或者HTML页面位于网站哪个地方,在action中填写MyProject/myServlet即可。

4、ServletConfig获得初始化参数

  • init方法中的ServletConfig对象

    • 在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。

    • 当Servlet配置了初始化参数后,web容器在创建Servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用Servlet的init方法时,将ServletConfig对象传递给Servlet。进而,程序员通过ServletConfig对象就可以得到当前Servlet的初始化参数信息。

  • 获取ServletConfig

    1. 创建一个Servlet

    2. 在web.xml 中 <servlet> 标签内 通过 <init-param> 标签 为Servlet配置初始化参数

       <init-param>
           <param-name>itcast</param-name>
           <param-value>传智播客</param-value>
       </init-param>
      
    3. 在Servlet程序中通过ServletConfig对象 获得itcast对应数据,ServletConfig有两个方法如下:

      • getInitParameter(String) ------ 通过name获得value

      • getInitParameterNames() ----- 获得所有name

  • 思考 :如何在doGet或doPost方法中获得Servlet初始化参数?

    将ServletConfig对象保存实例成员变量:

    GenericServlet已经将ServletConfig保存为成员变量 -----故在子类中通过getServletConfig方法获得初始化参数即可

  • 结论:子类Servlet不需要覆写init(ServletConfig), 只需要通过GenericServlet中 getServletConfig()方法来获得ServletConfig对象。

ServletConfig 配置初始化数据,只能在配置Servlet获得,其它Servlet无法获得 ----- 每个Servlet程序都对应一个ServletConfig对象

5、web引用对象——ServletContext(上下文)

  • web容器在启动时,它会为每一个web应用创建一个ServletContext对象,这个对象代表当前web应用。

  • 操作ServletContext必须通过ServletConfig获得对象。可以通过ServletConfig.getServletContext方法来获得ServletContext对象。

  • 由于一个web应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context对象。

  • 应用:

    1. 获得整个web应用初始化参数

      • 和ServletConfig对象有什么不同?

        如果用ServletConfig对象配置参数,只对配置的Servlet有效,如果通过ServletContext对象配置参数,所有的Servlet都可以访问。

      • 配置方法,在web.xml中添加如下格式的代码:

          <!-- 配置全局初始化参数,所有Servlet都可以 访问 -->
          <context-param>
              <param-name>hobby</param-name>
              <param-value>唱儿歌</param-value>    
          </context-param>
        
      • 获得 hobby 全局参数:

          // 通过ServletConfig 获得 ServletContext
          ServletContext context = getServletConfig().getServletContext();
        
          // 上面写法可以简化一下
          ServletContext context = getServletContext();
        
          // 读取全局初始化参数
          System.out.println(context.getInitParameter("hobby"));
        
    2. 实现全局数据共享

      • 预期效果:在ServletContext中 保存站点访问次数 ,每当一个用户访问站点,将访问次数+1。所有Servlet都可以获得该数据

      • 在CountServlet 初始化过程中,向ServletContext 保存访问次数为0。
        利用ServletContext.setAttribute("KEY","VALUE");

      • 代码实现(只显示init方法和doGet方法:

          public void init() throws ServletException {
              // 向ServletContext 保存访问次数 0
              // 获得ServletContext对象
              ServletContext context = getServletContext();
              // 保存数据 setAttribute
              context.setAttribute("visittimes", 0);
          }
        
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                  throws ServletException, IOException {
              // 每次访问 执行 doGet --- 将visittimes 次数 +1
        
              // 1、从ServletContext中获得 访问次数
              ServletContext context = getServletContext();
              int times = (Integer) context.getAttribute("visittimes");
        
              // 2、访问次数 +1
              times++;
        
              // 3、将访问次数更新回去 ServletContext
              context.setAttribute("visittimes", times);
        
              System.out.println("网站被访问了一次!");
          }
        
    3. 实现服务器端转发功能(少见,现在多用request、response)

      • 某Servlet的doGet中:

         // 交给下一个Servlet显示 ,将统计结果保存ServletContext
         ServletContext context = getServletContext();
         //times是int型数组
         context.setAttribute("times", times);
        
         // 转发跳转 另一个Servlet
         RequestDispatcher dispatcher = context
                 .getRequestDispatcher("/servlet/result"); // 这里面就是另一个Servlet的URL,绝对地址
         dispatcher.forward(request, response);
        
      • 在另一个Servlet的doGet中:

          ServletContext context = getServletContext();
          int[] times = (int[]) context.getAttribute("times");
          ...
        
    4. 读取web工程资源文件(必须使用绝对磁盘路径)

      • 使用java application 读取文件,读取当前工程下所有文件 ----- 使用相对路径读取文件。

      • 使用Servlet读取文件只能读取WebRoot下所有文件(注意Servlet是运行在tomcat中的) ---- 必须使用绝对磁盘路径读取文件

        • 如何获得绝对磁盘路径?

          • 通过站点根目录绝对路径获得磁盘绝对路径 ------ getServletContext().getRealPath("/WEB-INF/XXX.txt")

          • 因为 WEB-INF/classes 非常特殊 (存放.class文件目录),被类加载器加载,可以通过Class类对象读取该目录下文件(假设该Servlet名字叫做ReadFileServlet)。

              Class c = ReadFileServlet.class; // 通过Class对象读取文件                
              String filename3 = c.getResource("/a1.txt").getFile(); // 这里的"/" 等价于 "/WEB-INF/classes"
            

6、缺省Servlet

  • 如果某个Servlet的映射路径仅仅为一个正斜杠“/”,那么这个Servlet就成为当前web应用的缺省Servlet。

  • 凡是在web.xml文件中找不到匹配的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理其他Servlet都不处理的访问请求。

  • 在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet。

  • 当访问tomcat服务器中的某个静态HTML和图片时,实际上是在访问这个缺省的Servlet

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,874评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,151评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,270评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,137评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,116评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,935评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,261评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,895评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,342评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,854评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,978评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,609评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,181评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,182评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,402评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,376评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,677评论 2 344

推荐阅读更多精彩内容

  • Servlet学习的大纲 servlet概念及相关接口简介 servet 执行过程 servlet映射路径 缺省s...
    奋斗的老王阅读 1,183评论 1 51
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,184评论 11 349
  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,397评论 0 10
  • 本文包括:1、Listener简介2、Servlet监听器3、监听三个域对象创建和销毁的事件监听器4、监听三个域对...
    廖少少阅读 5,997评论 6 28
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,579评论 18 399