美文网首页
Servlet 教程——检视阅读(上)

Servlet 教程——检视阅读(上)

作者: 卡斯特梅的雨伞 | 来源:发表于2020-05-04 01:42 被阅读0次

    Servlet 教程——检视阅读

    参考

    Servlet教程——菜鸟——蓝本

    Servlet教程——w3cschool

    Servlet教程——易百

    servlet依赖maven依赖:

        <!--servlet依赖-->
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.0.1</version>
          <scope>provided</scope>
        </dependency>
    <!--    <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.1</version>
          <scope>provided</scope>
        </dependency>-->
    

    略读

    Servlet 为创建基于 web 的应用程序提供了基于组件、独立于平台的方法,可以不受 CGI 程序的性能限制。Servlet 有权限访问所有的 Java API,包括访问企业级数据库的 JDBC API。

    Servlet 是什么?

    Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

    使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

    Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:

    • 性能明显更好。
    • Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
    • Servlet 是独立于平台的,因为它们是用 Java 编写的。
    • 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
    • Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。

    Servlet 架构

    下图显示了 Servlet 在 Web 应用程序中的位置。

    Servlet 生命周期

    Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

    • Servlet 通过调用 init () 方法进行初始化。
    • Servlet 调用 service() 方法来处理客户端的请求。
    • Servlet 通过调用 destroy() 方法终止(结束)。
    • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

    Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。

    当用户调用一个 Servlet 时,就会创建一个 Servlet 实例(注意,这个实例是单例的,所有的请求都是在这个里面处理,HttpServletRequest才是原型的,每次请求会新建一个实例),每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。

    架构图

    下图显示了一个典型的 Servlet 生命周期方案。

    • 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
    • Servlet 容器在调用 service() 方法之前加载 Servlet。
    • 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。

    Servlet 处理表单数据,这些数据会根据不同的情况使用不同的方法自动解析:

    • getParameter():您可以调用 request.getParameter() 方法来获取表单参数的值。
    • getParameterValues():如果参数出现一次以上,则调用该方法,并返回多个值,例如复选框。
    • getParameterNames():如果您想要得到当前请求中的所有参数的完整列表,则调用该方法。

    Servlet 简介

    Servlet 是什么?

    Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

    使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

    Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:

    • 性能明显更好。
    • Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
    • Servlet 是独立于平台的,因为它们是用 Java 编写的。
    • 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
    • Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。

    Servlet 架构

    Servlet 包

    Java Servlet 是运行在带有支持 Java Servlet 规范的解释器的 web 服务器上的 Java 类。

    Servlet 可以使用 javax.servlet 和 javax.servlet.http 包创建,它是 Java 企业版的标准组成部分,Java 企业版是支持大型开发项目的 Java 类库的扩展版本。

    这些类实现 Java Servlet 和 JSP 规范。在写本教程的时候,二者相应的版本分别是 Java Servlet 2.5 和 JSP 2.1。

    Java Servlet 就像任何其他的 Java 类一样已经被创建和编译。在您安装 Servlet 包并把它们添加到您的计算机上的 Classpath 类路径中之后,您就可以通过 JDK 的 Java 编译器或任何其他编译器来编译 Servlet。

    Servlet 创建的三种方式。

    对于一个 Servlet 类,我们日常最常用的方法是继承自 HttpServlet 类,提供了 Http 相关的方法,HttpServlet 扩展了 GenericServlet 类,而 GenericServlet 类又实现了 Servlet 类和 ServletConfig 类。

    Servlet 类提供了五个方法,其中三个生命周期方法和两个普通方法 。 一个Servlet只会有一个对象,服务所有的请求(单例)。

    public interface Servlet {
        void init(ServletConfig var1) throws ServletException;
    
        ServletConfig getServletConfig();
    
        void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
        String getServletInfo();
    
        void destroy();
    }
    

    1、实现 Servlet 接口

    //Servlet的生命周期:从Servlet被创建到Servlet被销毁的过程
    //一次创建,到处服务
    //一个Servlet只会有一个对象,服务所有的请求
    /*
     * 1.实例化(使用构造方法创建对象)
     * 2.初始化  执行init方法
     * 3.服务     执行service方法
     * 4.销毁    执行destroy方法
     */
    public class ServletDemo1 implements Servlet {
    
        //public ServletDemo1(){}
    
         //生命周期方法:当Servlet第一次被创建对象时执行该方法,该方法在整个生命周期中只执行一次
        public void init(ServletConfig arg0) throws ServletException {
                    System.out.println("=======init=========");
            }
    
        //生命周期方法:对客户端响应的方法,该方法会被执行多次,每次请求该servlet都会执行该方法
        public void service(ServletRequest arg0, ServletResponse arg1)
                throws ServletException, IOException {
            System.out.println("hehe");
    
        }
    
        //生命周期方法:当Servlet被销毁时执行该方法
        public void destroy() {
            System.out.println("******destroy**********");
        }
    //当停止tomcat时也就销毁的servlet。
        public ServletConfig getServletConfig() {
    
            return null;
        }
    
        public String getServletInfo() {
    
            return null;
        }
    }
    

    2、继承 GenericServlet 类

    它实现了 Servlet 接口,重写 service 的方法,不过这种方法我们极少用。

    GenericServlet 是一个抽象类,实现了 Servlet 接口,并且对其中的 init() 和 destroy() 和 service() 提供了默认实现。在 GenericServlet 中,主要完成了以下任务:

    • 将 init() 中的 ServletConfig 赋给一个类级变量,可以由 getServletConfig 获得;

    • 为 Servlet 所有方法提供默认实现;

    • 可以直接调用 ServletConfig 中的方法;

      abstract class GenericServlet implements Servlet,ServletConfig{

       //GenericServlet通过将ServletConfig赋给类级变量
       private trServletConfig servletConfig;
      
       public void init(ServletConfig servletConfig) throws ServletException {
      
          this.servletConfig=servletConfig;
      
          /*自定义init()的原因是:如果子类要初始化必须覆盖父类的init() 而使它无效 这样
           this.servletConfig=servletConfig不起作用 这样就会导致空指针异常 这样如果子类要初始化,
           可以直接覆盖不带参数的init()方法 */
          this.init();
       }
       
       //自定义的init()方法,可以由子类覆盖  
       //init()不是生命周期方法
       public void init(){
      
       }
      
       //实现service()空方法,并且声明为抽象方法,强制子类必须实现service()方法 
       public abstract void service(ServletRequest request,ServletResponse response) 
         throws ServletException,java.io.IOException{
       }
      
       //实现空的destroy方法
       public void destroy(){ }
      

      }

    3、继承 HttpServlet 方法

    HttpServlet 也是一个抽象类,它进一步继承并封装了 GenericServlet,使得使用更加简单方便,由于是扩展了 Http 的内容,所以还需要使用 HttpServletRequest 和 HttpServletResponse,这两个类分别是 ServletRequest 和 ServletResponse 的子类

    HttpServlet 中对原始的 Servlet 中的方法都进行了默认的操作,不需要显式的销毁初始化以及 service(),在 HttpServlet 中,自定义了一个新的 service() 方法,其中通过 getMethod() 方法判断请求的类型,从而调用 doGet() 或者 doPost() 处理 get,post 请求,使用者只需要继承 HttpServlet,然后重写 doPost() 或者 doGet() 方法处理请求即可。

    我们一般都使用继承 HttpServlet 的方式来定义一个 servlet。

    注意:

    service() 是线程安全的。

    Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法 。这种多线程是线程安全的,因为我们的service(HttpServletRequest req, HttpServletResponse resp)方法传入的参数

    HttpServletRequest req, HttpServletResponse resp都是自己的,虽然只有一个实例,但service方法里面没有调用到类成员变量等共享资源,就不会有线程安全的问题;而在service方法里,虽然只有一个实例,我们假设两个请求同时到该方法中,也是没有问题的,因为局部变量是线程安全的,每个请求调用service方法都会开辟一个栈空间存储局部变量,是不会串位的,这是由于方法直接是线程隔离的,不要担心同时请求导致变量串了。

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }
    
    }
    

    Servlet 生命周期

    Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

    • Servlet 通过调用 init () 方法进行初始化。
    • Servlet 调用 service() 方法来处理客户端的请求。
    • Servlet 通过调用 destroy() 方法终止(结束)。
    • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

    init() 方法

    init 方法被设计成只调用一次。它在第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。

    Servlet 创建于用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。

    当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。

    service() 方法

    service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

    每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

    service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。

    doGet() 方法

    GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。

    doPost() 方法

    POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。

    destroy() 方法

    destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

    Servlet生命周期架构图

    下图显示了一个典型的 Servlet 生命周期方案。

    • 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
    • Servlet 容器在调用 service() 方法之前加载 Servlet。
    • 然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。

    Servlet 实例

    Servlet 是服务 HTTP 请求并实现 javax.servlet.Servlet 接口的 Java 类。Web 应用程序开发人员通常编写 Servlet 来扩展 javax.servlet.http.HttpServlet,并实现 Servlet 接口的抽象类专门用来处理 HTTP 请求。

    报错:路径重名的话tomcat启动不了。

    servlet 浏览器访问路径配置有个小问题:

    1、java 类里的注解 —— @WebServlet("/HelloServlet") 对应浏览器路径:

    http://localhost:8080/TomcatTest/HelloServlet
    

    2、配置文件(web.xml)里对应的浏览器访问路径:

    http://localhost:8080/TomcatTest/HelloServlet
    

    这两种配一个就好了,不然路径重名的话反而会让tomcat启动不了。

    例如这样就启动不了:

    修改 web.xml :

    <url-pattern>/HelloServlet</url-pattern>
    

    修改后,web.xml 和 java 类的注解,对应路径都是:

    http://localhost:8080/TomcatTest/HelloServlet
    

    导致

    命名的 servlet[HelloServlet]和 [com.runoob.test.HelloServlet] 都被映射到 URL 模式 [/ HelloServlet] 这是不允许的。
    

    解决办法:

    将注解去掉或者保留注解进入web.xml将映射删除既可以。

    示例:

    //@WebServlet("/HelloWorld")
    public class HelloWorld extends HttpServlet {
    
        private String message;
    
        @Override
        public void init() throws ServletException
        {
            // 执行必需的初始化
            message = "Hello World";
        }
        @Override
        public void doGet(HttpServletRequest request,
                          HttpServletResponse response)
                throws ServletException, IOException
        {
            // 设置响应内容类型
            response.setContentType("text/html");
    
            // 实际的逻辑是在这里
            PrintWriter out = response.getWriter();
            out.println("<h1>" + message.toUpperCase() + "</h1>");
        }
        @Override
        public void destroy()
        {
            // 什么也不做
        }
    }
    

    web.xml

    <servlet>
      <servlet-name>HelloWorld</servlet-name>
      <servlet-class>com.jsptest.HelloWorld</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>HelloWorld</servlet-name>
      <url-pattern>/HelloWorld</url-pattern>
    </servlet-mapping>
    

    Servlet 表单数据

    很多情况下,需要传递一些信息,从浏览器到 Web 服务器,最终到后台程序。浏览器使用两种方法可将这些信息传递到 Web 服务器,分别为 GET 方法和 POST 方法。

    GET 方法

    GET 方法向页面请求发送已编码的用户信息。页面和已编码的信息中间用 ? 字符分隔,如下所示:

    http://www.test.com/hello?key1=value1&key2=value2
    

    GET 方法是默认的从浏览器向 Web 服务器传递信息的方法,它会产生一个很长的字符串,出现在浏览器的地址栏中。如果您要向服务器传递的是密码或其他的敏感信息,请不要使用 GET 方法。GET 方法有大小限制:请求字符串中最多只能有 1024 个字符。

    这些信息使用 QUERY_STRING 头传递,并可以通过 QUERY_STRING 环境变量访问,Servlet 使用 doGet() 方法处理这种类型的请求。

    POST 方法

    另一个向后台程序传递信息的比较可靠的方法是 POST 方法。POST 方法打包信息的方式与 GET 方法基本相同,但是 POST 方法不是把信息作为 URL 中 ? 字符后的文本字符串进行发送,而是把这些信息作为一个单独的消息。消息以标准输出的形式传到后台程序,您可以解析和使用这些标准输出。Servlet 使用 doPost() 方法处理这种类型的请求。

    使用 Servlet 读取表单数据

    Servlet 处理表单数据,这些数据会根据不同的情况使用不同的方法自动解析:

    • getParameter():您可以调用 request.getParameter() 方法来获取表单参数的值。
    • getParameterValues():如果参数出现一次以上,则调用该方法,并返回多个值,例如复选框。
    • getParameterNames():如果您想要得到当前请求中的所有参数的完整列表,则调用该方法。

    示例:

    hellomybatis-servlet.xml 响应字符编码设置为utf-8

    <!-- 消息转换器代码,处理请求返回json字符串的中文乱码问题 -->
    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=UTF-8</value>
                        <!--<value>application/json;charset=UTF-8</value>-->
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

    web.xml 请求字符编码过滤为utf-8

    <!-- 字符编码过滤器 -->
    <filter>
      <filter-name>encodingFilter</filter-name>
      <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
      <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>encodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    //加了@WebServlet 注解就不用在web.xml配置servlet
    @WebServlet("/show")
    public class ShowServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          resp.setContentType("text/html;charset=utf-8");
            PrintWriter writer = resp.getWriter();
            String title = "GET 获取称号";
            //不需要转译编码的原因是
            //String name = new String(req.getParameter("name").getBytes("ISO-8859-1"), "UTF-8");
            //String titleName = new String(req.getParameter("title").getBytes("ISO-8859-1"), "UTF-8");
            String docType = "<!DOCTYPE html> \n";
            writer.println(docType +
                    "<html>\n" +
                    "<head><title>" + title + "</title></head>\n" +
                    "<body bgcolor=\"#f0f0f0\">\n" +
                    "<h1 align=\"center\">" + title + "</h1>\n" +
                    "<ul>\n" +
                    "  <li><b>人物</b>:"
                    + req.getParameter("name") + "\n" +
                    "  <li><b>称号</b>:"
                    + req.getParameter("title") + "\n" +
                    "</ul>\n" +
                    "</body></html>");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req,resp);
        }
    }
    

    输出:

    表单提交get示例:

    web.xml

      <servlet>
        <servlet-name>hellomybatis</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>
            WEB-INF/hellomybatis-servlet.xml
          </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>hellomybatis</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.xml</url-pattern>
      </servlet-mapping>
      <!--如果是*.html则不走代理,走默认请求到html文件上-->
      <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.html</url-pattern>
      </servlet-mapping>
    

    show.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>佣兵天下</title>
    </head>
    <body>
    <form action="/hellomybatis/show" method="GET">
        人物:<input type="text" name="name">
        <br />
        称号:<input type="text" name="title" />
        <input type="submit" value="提交" />
    </form>
    </body>
    </html>
    

    ShowServlet 不变。

    使用表单的 POST 方法实例:

    只需要把请求改成post,后台对应重写doPost()方法即可。

     <form action="/hellomybatis/show" method="POST">
        人物:<input type="text" name="name">
        <br />
        称号:<input type="text" name="title" />
        <input type="submit" value="提交" />
    </form>
    

    Servlet 客户端 HTTP 请求

    当浏览器请求网页时,它会向 Web 服务器发送特定信息,这些信息不能被直接读取,因为这些信息是作为 HTTP 请求的头的一部分进行传输的。您可以查看 HTTP 协议 了解更多相关信息。

    以下是来自于浏览器端的重要头信息,您可以在 Web 编程中频繁使用:

    头信息 描述
    Accept 这个头信息指定浏览器或其他客户端可以处理的 MIME 类型。值 image/png 或 image/jpeg 是最常见的两种可能值。
    Accept-Charset 这个头信息指定浏览器可以用来显示信息的字符集。例如 ISO-8859-1。
    Accept-Encoding 这个头信息指定浏览器知道如何处理的编码类型。值 gzip 或 compress 是最常见的两种可能值。
    Accept-Language 这个头信息指定客户端的首选语言,在这种情况下,Servlet 会产生多种语言的结果。例如,en、en-us、ru 等。
    Authorization 这个头信息用于客户端在访问受密码保护的网页时识别自己的身份。
    Connection 这个头信息指示客户端是否可以处理持久 HTTP 连接。持久连接允许客户端或其他浏览器通过单个请求来检索多个文件。值 Keep-Alive 意味着使用了持续连接。
    Content-Length 这个头信息只适用于 POST 请求,并给出 POST 数据的大小(以字节为单位)。
    Cookie 这个头信息把之前发送到浏览器的 cookies 返回到服务器。
    Host 这个头信息指定原始的 URL 中的主机和端口。
    If-Modified-Since 这个头信息表示只有当页面在指定的日期后已更改时,客户端想要的页面。如果没有新的结果可以使用,服务器会发送一个 304 代码,表示 Not Modified 头信息。
    If-Unmodified-Since 这个头信息是 If-Modified-Since 的对立面,它指定只有当文档早于指定日期时,操作才会成功。
    Referer 这个头信息指示所指向的 Web 页的 URL。例如,如果您在网页 1,点击一个链接到网页 2,当浏览器请求网页 2 时,网页 1 的 URL 就会包含在 Referer 头信息中。
    User-Agent 这个头信息识别发出请求的浏览器或其他客户端,并可以向不同类型的浏览器返回不同的内容。

    读取 HTTP 头的方法

    下面的方法可用在 Servlet 程序中读取 HTTP 头。这些方法通过 HttpServletRequest 对象可用。

    序号 方法 & 描述
    1 Cookie[] getCookies() 返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。
    2 Enumeration getAttributeNames() 返回一个枚举,包含提供给该请求可用的属性名称。
    3 Enumeration getHeaderNames() 返回一个枚举,包含在该请求中包含的所有的头名。
    4 Enumeration getParameterNames() 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。
    5 HttpSession getSession() 返回与该请求关联的当前 session 会话,或者如果请求没有 session 会话,则创建一个。
    6 HttpSession getSession(boolean create) 返回与该请求关联的当前 HttpSession,或者如果没有当前会话,且创建是真的,则返回一个新的 session 会话。
    7 Locale getLocale() 基于 Accept-Language 头,返回客户端接受内容的首选的区域设置。
    8 Object getAttribute(String name) 以对象形式返回已命名属性的值,如果没有给定名称的属性存在,则返回 null。
    9 ServletInputStream getInputStream() 使用 ServletInputStream,以二进制数据形式检索请求的主体。
    10 String getAuthType() 返回用于保护 Servlet 的身份验证方案的名称,例如,"BASIC" 或 "SSL",如果JSP没有受到保护则返回 null。
    11 String getCharacterEncoding() 返回请求主体中使用的字符编码的名称。
    12 String getContentType() 返回请求主体的 MIME 类型,如果不知道类型则返回 null。
    13 String getContextPath() 返回指示请求上下文的请求 URI 部分。
    14 String getHeader(String name) 以字符串形式返回指定的请求头的值。
    15 String getMethod() 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
    16 String getParameter(String name) 以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。
    17 String getPathInfo() 当请求发出时,返回与客户端发送的 URL 相关的任何额外的路径信息。
    18 String getProtocol() 返回请求协议的名称和版本。
    19 String getQueryString() 返回包含在路径后的请求 URL 中的查询字符串。
    20 String getRemoteAddr() 返回发送请求的客户端的互联网协议(IP)地址。
    21 String getRemoteHost() 返回发送请求的客户端的完全限定名称。
    22 String getRemoteUser() 如果用户已通过身份验证,则返回发出请求的登录用户,或者如果用户未通过身份验证,则返回 null。
    23 String getRequestURI() 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。
    24 String getRequestedSessionId() 返回由客户端指定的 session 会话 ID。
    25 String getServletPath() 返回调用 JSP 的请求的 URL 的一部分。
    26 String[] getParameterValues(String name) 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。
    27 boolean isSecure() 返回一个布尔值,指示请求是否使用安全通道,如 HTTPS。
    28 int getContentLength() 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。
    29 int getIntHeader(String name) 返回指定的请求头的值为一个 int 值。
    30 int getServerPort() 返回接收到这个请求的端口号。
    31 int getParameterMap() 将参数封装成 Map 类型。

    示例:

    @WebServlet("/displayHeaderServlet")
    public class DisplayHeaderServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
        // 处理 GET 方法请求的方法
        @Override
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
        {
            // 设置响应内容类型
            //如果不设置会导致乱码
            //HTTP Header ???? - ??????
            response.setContentType("text/html;charset=UTF-8");
    
            PrintWriter out = response.getWriter();
            String title = "HTTP Header 请求响应头";
            String docType =
                    "<!DOCTYPE html> \n";
            out.println(docType +
                    "<html>\n" +
                    "<head><meta charset=\"utf-8\"><title>" + title + "</title></head>\n"+
                    "<body bgcolor=\"#f0f0f0\">\n" +
                    "<h1 align=\"center\">" + title + "</h1>\n" +
                    "<table width=\"100%\" border=\"1\" align=\"center\">\n" +
                    "<tr bgcolor=\"#949494\">\n" +
                    "<th>Header 名称</th><th>Header 值</th>\n"+
                    "</tr>\n");
    
            Enumeration headerNames = request.getHeaderNames();
    
            while(headerNames.hasMoreElements()) {
                String paramName = (String)headerNames.nextElement();
                out.print("<tr><td>" + paramName + "</td>\n");
                String paramValue = request.getHeader(paramName);
                out.println("<td> " + paramValue + "</td></tr>\n");
            }
            out.println("</table>\n</body></html>");
        }
        // 处理 POST 方法请求的方法
        @Override
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
    }
    

    输出:

    报错:

    1、Class com.jsptest.DisplayHeaderServlet is not a Servlet

    这是因为我们在给DisplayHeaderServlet加上@WebServlet时却没有继承HttpServlet,导致系统初始化Servlet时因为DisplayHeaderServlet没有初始化init()和destroy()等默认方法无法初始化而报错。

    javax.servlet.ServletException: Class com.jsptest.DisplayHeaderServlet is not a Servlet
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:522)
    

    2、Failed to start component

    这是因为@WebServlet("displayHeaderServlet")注解没有加/ 斜杠导致的servlet不能加载。

    Caused by: java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/hellomybatis]]
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:730)
    
    @WebServlet("displayHeaderServlet")
    public class DisplayHeaderServlet extends HttpServlet {
        /......
    }
    
    //正确写法
    @WebServlet("/displayHeaderServlet")
    public class DisplayHeaderServlet extends HttpServlet {
        /......
    }
    

    Servlet 服务器 HTTP 响应

    状态行包括 HTTP 版本(在本例中为 HTTP/1.1)、一个状态码(在本例中为 200)和一个对应于状态码的短消息(在本例中为 OK)。

    下表总结了从 Web 服务器端返回到浏览器的最有用的 HTTP 1.1 响应报头,您会在 Web 编程中频繁地使用它们:

    头信息 描述
    Allow 这个头信息指定服务器支持的请求方法(GET、POST 等)。
    Cache-Control 这个头信息指定响应文档在何种情况下可以安全地缓存。可能的值有:public、private 或 no-cache 等。Public 意味着文档是可缓存,Private 意味着文档是单个用户私用文档,且只能存储在私有(非共享)缓存中,no-cache 意味着文档不应被缓存。
    Connection 这个头信息指示浏览器是否使用持久 HTTP 连接。值 close 指示浏览器不使用持久 HTTP 连接,值 keep-alive 意味着使用持久连接。
    Content-Disposition 这个头信息可以让您请求浏览器要求用户以给定名称的文件把响应保存到磁盘。
    Content-Encoding 在传输过程中,这个头信息指定页面的编码方式。
    Content-Language 这个头信息表示文档编写所使用的语言。例如,en、en-us、ru 等。
    Content-Length 这个头信息指示响应中的字节数。只有当浏览器使用持久(keep-alive)HTTP 连接时才需要这些信息。
    Content-Type 这个头信息提供了响应文档的 MIME(Multipurpose Internet Mail Extension)类型。
    Expires 这个头信息指定内容过期的时间,在这之后内容不再被缓存。
    Last-Modified 这个头信息指示文档的最后修改时间。然后,客户端可以缓存文件,并在以后的请求中通过 If-Modified-Since 请求头信息提供一个日期。
    Location 这个头信息应被包含在所有的带有状态码的响应中。在 300s 内,这会通知浏览器文档的地址。浏览器会自动重新连接到这个位置,并获取新的文档。
    Refresh 这个头信息指定浏览器应该如何尽快请求更新的页面。您可以指定页面刷新的秒数。
    Retry-After 这个头信息可以与 503(Service Unavailable 服务不可用)响应配合使用,这会告诉客户端多久就可以重复它的请求。
    Set-Cookie 这个头信息指定一个与页面关联的 cookie。

    设置 HTTP 响应报头的方法

    下面的方法可用于在 Servlet 程序中设置 HTTP 响应报头。这些方法通过 HttpServletResponse 对象可用。

    序号 方法 & 描述
    1 String encodeRedirectURL(String url) 为 sendRedirect 方法中使用的指定的 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。
    2 String encodeURL(String url) 对包含 session 会话 ID 的指定 URL 进行编码,或者如果编码不是必需的,则返回 URL 未改变。
    3 boolean containsHeader(String name) 返回一个布尔值,指示是否已经设置已命名的响应报头。
    4 boolean isCommitted() 返回一个布尔值,指示响应是否已经提交。
    5 void addCookie(Cookie cookie) 把指定的 cookie 添加到响应。
    6 void addDateHeader(String name, long date) 添加一个带有给定的名称和日期值的响应报头。
    7 void addHeader(String name, String value) 添加一个带有给定的名称和值的响应报头。
    8 void addIntHeader(String name, int value) 添加一个带有给定的名称和整数值的响应报头。
    9 void flushBuffer() 强制任何在缓冲区中的内容被写入到客户端。
    10 void reset() 清除缓冲区中存在的任何数据,包括状态码和头。
    11 void resetBuffer() 清除响应中基础缓冲区的内容,不清除状态码和头。
    12 void sendError(int sc) 使用指定的状态码发送错误响应到客户端,并清除缓冲区。
    13 void sendError(int sc, String msg) 使用指定的状态发送错误响应到客户端。
    14 void sendRedirect(String location) 使用指定的重定向位置 URL 发送临时重定向响应到客户端。
    15 void setBufferSize(int size) 为响应主体设置首选的缓冲区大小。
    16 void setCharacterEncoding(String charset) 设置被发送到客户端的响应的字符编码(MIME 字符集)例如,UTF-8。
    17 void setContentLength(int len) 设置在 HTTP Servlet 响应中的内容主体的长度,该方法设置 HTTP Content-Length 头。
    18 void setContentType(String type) 如果响应还未被提交,设置被发送到客户端的响应的内容类型。
    19 void setDateHeader(String name, long date) 设置一个带有给定的名称和日期值的响应报头。
    20 void setHeader(String name, String value) 设置一个带有给定的名称和值的响应报头。
    21 void setIntHeader(String name, int value) 设置一个带有给定的名称和整数值的响应报头。
    22 void setLocale(Locale loc) 如果响应还未被提交,设置响应的区域。
    23 void setStatus(int sc) 为该响应设置状态码。

    示例:

    @WebServlet("/refresh")
    public class RefreshServlet extends HttpServlet {
        // 处理 GET 方法请求的方法
        @Override
        public void doGet(HttpServletRequest request,
                          HttpServletResponse response)
                throws ServletException, IOException
        {
            // 设置刷新自动加载时间为 3秒
            response.setIntHeader("Refresh", 3);
            // 设置响应内容类型
            response.setContentType("text/html;charset=UTF-8");
            Cookie cookie = new Cookie("winner","amy");
            response.addCookie(cookie);
            //使用默认时区和语言环境获得一个日历
            Calendar cale = Calendar.getInstance();
            //将Calendar类型转换成Date类型
            Date tasktime=cale.getTime();
            //设置日期输出的格式
            SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //格式化输出
            String nowTime = df.format(tasktime);
            PrintWriter out = response.getWriter();
            String title = "自动刷新 Header 页面";
            String docType =
                    "<!DOCTYPE html>\n";
            out.println(docType +
                    "<html>\n" +
                    "<head><title>" + title + "</title></head>\n"+
                    "<body bgcolor=\"#f0f0f0\">\n" +
                    "<h1 align=\"center\">" + title + "</h1>\n" +
                    "<p>当前时间是:" + nowTime + "</p>\n");
        }
        // 处理 POST 方法请求的方法
        @Override
        public void doPost(HttpServletRequest request,
                           HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    }
    

    输出:

    扩展:Cookie是跟着session会话走的,我们请求的链接如果加了Cookie,就是对整个会话加Cookie,后面的请求都会带上这个Cookie。查看Cookie的两种方式。一个从network,一个从application.

    Servlet HTTP 状态码

    状态行包括 HTTP 版本(在本例中为 HTTP/1.1)、一个状态码(在本例中为 200)和一个对应于状态码的短消息(在本例中为 OK)。

    以下是可能从 Web 服务器返回的 HTTP 状态码和相关的信息列表:

    代码 消息 描述
    100 Continue 只有请求的一部分已经被服务器接收,但只要它没有被拒绝,客户端应继续该请求。
    101 Switching Protocols 服务器切换协议。
    200 OK 请求成功。
    201 Created 该请求是完整的,并创建一个新的资源。
    202 Accepted 该请求被接受处理,但是该处理是不完整的。
    203 Non-authoritative Information
    204 No Content
    205 Reset Content
    206 Partial Content
    300 Multiple Choices 链接列表。用户可以选择一个链接,进入到该位置。最多五个地址。
    301 Moved Permanently 所请求的页面已经转移到一个新的 URL。
    302 Found 所请求的页面已经临时转移到一个新的 URL。
    303 See Other 所请求的页面可以在另一个不同的 URL 下被找到。
    304 Not Modified
    305 Use Proxy
    306 Unused 在以前的版本中使用该代码。现在已不再使用它,但代码仍被保留。
    307 Temporary Redirect 所请求的页面已经临时转移到一个新的 URL。
    400 Bad Request 服务器不理解请求。
    401 Unauthorized 所请求的页面需要用户名和密码。
    402 Payment Required 您还不能使用该代码。
    403 Forbidden 禁止访问所请求的页面。
    404 Not Found 服务器无法找到所请求的页面。.
    405 Method Not Allowed 在请求中指定的方法是不允许的。
    406 Not Acceptable 服务器只生成一个不被客户端接受的响应。
    407 Proxy Authentication Required 在请求送达之前,您必须使用代理服务器的验证。
    408 Request Timeout 请求需要的时间比服务器能够等待的时间长,超时。
    409 Conflict 请求因为冲突无法完成。
    410 Gone 所请求的页面不再可用。
    411 Length Required "Content-Length" 未定义。服务器无法处理客户端发送的不带 Content-Length 的请求信息。
    412 Precondition Failed 请求中给出的先决条件被服务器评估为 false。
    413 Request Entity Too Large 服务器不接受该请求,因为请求实体过大。
    414 Request-url Too Long 服务器不接受该请求,因为 URL 太长。当您转换一个 "post" 请求为一个带有长的查询信息的 "get" 请求时发生。
    415 Unsupported Media Type 服务器不接受该请求,因为媒体类型不被支持。
    417 Expectation Failed
    500 Internal Server Error 未完成的请求。服务器遇到了一个意外的情况。
    501 Not Implemented 未完成的请求。服务器不支持所需的功能。
    502 Bad Gateway 未完成的请求。服务器从上游服务器收到无效响应。
    503 Service Unavailable 未完成的请求。服务器暂时超载或死机。
    504 Gateway Timeout 网关超时。
    505 HTTP Version Not Supported 服务器不支持"HTTP协议"版本。

    设置 HTTP 状态代码的方法

    下面的方法可用于在 Servlet 程序中设置 HTTP 状态码。这些方法通过 HttpServletResponse 对象可用。

    序号 方法 & 描述
    1 public void setStatus ( int statusCode ) 该方法设置一个任意的状态码。setStatus 方法接受一个 int(状态码)作为参数。如果您的响应包含了一个特殊的状态码和文档,请确保在使用 PrintWriter 实际返回任何内容之前调用 setStatus。
    2 public void sendRedirect(String url) 该方法生成一个 302 响应,连同一个带有新文档 URL 的 Location 头。
    3 public void sendError(int code, String message) 该方法发送一个状态码(通常为 404),连同一个在 HTML 文档内部自动格式化并发送到客户端的短消息。

    示例:

    @WebServlet("/error")
    public class ErrorServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setStatus(403);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           doGet(req,resp);
        }
    }
    

    输出:

    Servlet 编写过滤器

    Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。

    filter对象只会创建一次,init方法也只会执行一次。

    可以将一个或多个 Servlet 过滤器附加到一个 Servlet 或一组 Servlet。Servlet 过滤器也可以附加到 JavaServer Pages (JSP) 文件和 HTML 页面。调用 Servlet 前调用所有附加的 Servlet 过滤器。

    Servlet 过滤器是可用于 Servlet 编程的 Java 类,可以实现以下目的:

    • 在客户端的请求访问后端资源之前,拦截这些请求。
    • 在服务器的响应发送回客户端之前,处理这些响应。

    根据规范建议的各种类型的过滤器:

    • 身份验证过滤器(Authentication Filters)。
    • 数据压缩过滤器(Data compression Filters)。
    • 加密过滤器(Encryption Filters)。
    • 触发资源访问事件过滤器。
    • 图像转换过滤器(Image Conversion Filters)。
    • 日志记录和审核过滤器(Logging and Auditing Filters)。
    • MIME-TYPE 链过滤器(MIME-TYPE Chain Filters)。
    • 标记化过滤器(Tokenizing Filters)。
    • XSL/T 过滤器(XSL/T Filters),转换 XML 内容。

    过滤器通过 Web 部署描述符(web.xml)中的 XML 标签来声明,然后映射到您的应用程序的部署描述符中的 Servlet 名称或 URL 模式。

    当 Web 容器启动 Web 应用程序时,它会为您在部署描述符中声明的每一个过滤器创建一个实例。

    Filter的执行顺序与在web.xml配置文件中的配置顺序一致,一般把Filter配置在所有的Servlet之前。

    Servlet 过滤器方法

    过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类。javax.servlet.Filter 接口定义了三个方法:

    序号 方法 & 描述
    1 public void doFilter (ServletRequest, ServletResponse, FilterChain) 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。
    2 public void init(FilterConfig filterConfig) web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)。开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。
    3 public void destroy() Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。

    示例:

    public class LogFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            String before = filterConfig.getInitParameter("before");
            // 输出初始化参数
            System.out.println("初始化前:" + before);
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            System.out.println("过滤时执行参数输出:"+ JSON.toJSONString(servletRequest.getParameterMap()));
            // 把请求传回过滤链
            filterChain.doFilter(servletRequest,servletResponse);
        }
    
        @Override
        public void destroy() {
            System.out.println("关闭 LogFilter");
        }
    }
    

    web.xml

    <filter>
      <filter-name>LogFilter</filter-name>
      <filter-class>com.filter.LogFilter</filter-class>
      <init-param>
        <param-name>before</param-name>
        <param-value>日志打印</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>LogFilter</filter-name>
      <!--过滤器适用于所有的 Servlet,因为我们在配置中指定 /* ,url-pattern用于匹配我们想要过滤的请求路径-->
      <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    请求:<http://localhost:8080/hellomybatis/show?name=amy&title=屠龙勇士

    输出:

    使用多个过滤器

    Web 应用程序可以根据特定的目的定义若干个不同的过滤器。假设您定义了两个过滤器 AuthenFilter 和 LogFilter。

    项目启动时会初始化filter过滤器,初始化是随机的,不一定以web.xml配置的一样。使用多个过滤器以在web.xml配置的先后顺序执行。

    示例:

    web.xml

    <filter>
      <filter-name>LogFilter</filter-name>
      <filter-class>com.filter.LogFilter</filter-class>
      <init-param>
        <param-name>before</param-name>
        <param-value>日志打印</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>LogFilter</filter-name>
      <!--过滤器适用于所有的 Servlet,因为我们在配置中指定 /* ,url-pattern用于匹配我们想要过滤的请求路径-->
      <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <filter>
      <filter-name>AuthenFilter</filter-name>
      <filter-class>com.filter.AuthenFilter</filter-class>
      <init-param>
        <param-name>authen</param-name>
        <param-value>权限校验</param-value>
      </init-param>
    </filter>
      <filter-mapping>
        <filter-name>AuthenFilter</filter-name>
        <!--过滤器适用于所有的 Servlet,因为我们在配置中指定 /* ,url-pattern用于匹配我们想要过滤的请求路径-->
        <!--<url-pattern>/*</url-pattern>-->
        <!--只适用于@WebServlet("/show")-->
        <url-pattern>/show</url-pattern>
        <!--不能进入-->
        <!--<url-pattern>/showyyy</url-pattern>-->
        <!--也可以用<servlet-name>指定过滤器所拦截的Servlet名称,不过该名字必须配置在web.xml中,不能用注解,否则不能识别-->
        <!--<servlet-name></servlet-name>-->
      </filter-mapping>
    
    public class AuthenFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            String authen = filterConfig.getInitParameter("authen");
            // 输出初始化参数
            System.out.println("初始化前:" + authen);
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            //获取请求信息(测试时可以通过get方式在URL中添加name)
            String name = servletRequest.getParameter("name");
    
            // 过滤器核心代码逻辑
            System.out.println("过滤器获取请求参数:"+name);
            System.out.println("AuthenFilter 过滤");
    
            if("amy".equals(name)){
                // 把请求传回过滤链
                filterChain.doFilter(servletRequest, servletResponse);
            }else{
                //设置返回内容类型
                servletResponse.setContentType("text/html;charset=UTF-8");
    
                //在页面输出响应信息
                PrintWriter out = servletResponse.getWriter();
                out.print("<b>:"+name+"不正确,请求被拦截,不能访问web资源</b>");
                System.out.println("name:"+name+"不正确,请求被拦截,不能访问web资源");
            }
        }
    
        @Override
        public void destroy() {
            System.out.println("关闭 LogFilter");
        }
    }
    

    请求:<http://localhost:8080/hellomybatis/show?name=amy&title=屠龙勇士

    请求:<http://localhost:8080/hellomybatis/show?name=happ&title=屠龙勇士

    输出:

    初始化前:权限校验
    初始化前:日志打印
    过滤时执行参数输出:{"name":["amy"],"title":["屠龙勇士"]}
    过滤器获取请求参数:amy
    AuthenFilter 过滤
    过滤时执行参数输出:{"name":["happ"],"title":["屠龙勇士"]}
    过滤器获取请求参数:happ
    AuthenFilter 过滤
    name:happ不正确,请求被拦截,不能访问web资源
    

    过滤器的应用顺序

    web.xml 中的 filter-mapping 元素的顺序决定了 Web 容器应用过滤器到 Servlet 的顺序。若要反转过滤器的顺序,您只需要在 web.xml 文件中反转 filter-mapping 元素即可

    web.xml配置各节点说明

    <filter>指定一个过滤器。
    <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
    <filter-class>元素用于指定过滤器的完整的限定类名。
    <init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。
    在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。
    <filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
    <filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
    <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
    <servlet-name>指定过滤器所拦截的Servlet名称。
    <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher>子元素用来指定 Filter 对资源的多种调用方式进行拦截。
    <dispatcher>子元素可以设置的值及其意义
    REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
    INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
    FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
    ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
    

    相关文章

      网友评论

          本文标题:Servlet 教程——检视阅读(上)

          本文链接:https://www.haomeiwen.com/subject/bsisghtx.html