zoukankan      html  css  js  c++  java
  • Servlet 学习(八)

    Filter

    1、功能

    • Java Servlet 2.3 中新增加的功能,主要作用是对Servlet 容器的请求和响应进行检查和修改
    • Filter 本身并不生成请求和响应对象,它只提供过滤作用

        在Servlet 被调用之前,检查Request 对象
          »可以对其Request Header 和Request 内容进行审查和修改
        在Servlet 调用结束之后,检查Response 对象
          »可以对其Response Header 和Response 内容进行审查和修改

    • Filter 可以过滤的Web 组件包括Servlet,JSP,HTML等
    • Filter主要负责拦截请求,和放行。
    • Filter 过滤过程

    2、接口Filter

    • init( FilterConfig config )

        Filter 的初始化方法
        容器创建Filter 之后将调用这个方法
        使用这个方法可以读取web.xml 文件中定义的初始化参数

    • doFilter(ServletRequest req,ServletResponse resp ,FilterChain chain)

        该方法完成实际的过滤操作
        当客户请求访问与Filter 相关联的URL 时,将调用该方法
        chain 用于访问后续的Filter 或Servlet

    • destroy()

        容器在销毁Filter 实例前调用该方法
        该方法中可以释放该Filter 所占用的资源

    • Filter的生命周期

        Filter的创建和销毁由web服务器控制。

          »服务器启动的时候,web服务器创建Filter的实例对象,并调用其init方法,完成对象的初始化功能。filter对象只会创建一次,init方法也只会执行一次。

          »拦截到请求时,执行doFilter方法。可以执行多次。

          »服务器关闭时,web服务器销毁Filter的实例对象。

    3、接口FilterChain

    • 过滤器链
    • 一组过滤器对某些web资源进行拦截,那么这组过滤器就称为过滤器链。过滤器的执行顺序和<filter-mapping>有关

    • 该接口中定义的方法

        doFilter(ServletRequest req,ServletResponse resp )
          »负责把所有的过滤器给串联起来
          »使得一个过滤器执行完后,下一个可以继续执行
          »被串联的多个过滤器按照配置文件中的映射顺序依次执行

    4、创建Filter

    • 实现Filter
    package ecut.filter.filter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class HelloFilter implements Filter {
        
        public void init(FilterConfig config) throws ServletException {
        }
    
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
            // place your code here
            System.out.println( "hello" );
            
            // pass the request along the filter chain
            chain.doFilter( req, resp ); 
            
            System.out.println( "world" );
        }
    
        public void destroy() {
        }
    
    }
    • 注册Filter
    <filter>
        <filter-name>HelloFilter</filter-name>
        <filter-class>ecut.filter.filter.HelloFilter</filter-class>
    </filter>
    • 发布Filter

        同Servlet 一样,url-pattern 可以写多个

        url-mapping匹配规则有三种:

          »精确匹配 —— 如/index.html,只会匹配index.html这个URL

          »路径匹配 —— 如/*,会匹配所有的URL

          »后缀匹配 —— 如*.html,会匹配所有以.html为后缀的URL

    <filter-mapping>
        <filter-name>HelloFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    • 测试案例
    package ecut.filter.servlet;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class HelloServlet extends HttpServlet {
    
        private static final long serialVersionUID = -8731391727918781480L;
    
        @Override
        protected void service( HttpServletRequest request, HttpServletResponse response ) 
                throws ServletException, IOException {
            
            System.out.println( "service" );
            
            response.setContentType( "text/html" );
            
            PrintWriter w = response.getWriter();
            
            w.println( "<h2 style='text-align:center;'>你好 , Servlet .</h2>" );
            
        }
        
        
    
    }
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>ecut.filter.servlet.HelloServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
         <servlet-name>HelloServlet</servlet-name>
         <url-pattern>/filter/hello</url-pattern>
    </servlet-mapping>    

    在浏览器中访问HelloServle

    运行结果如下:

    hello
    service
    world

     

    5、在config中指定初始化参数

    • 用 户在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其 init方法时,会把封装了filter初始化参数的filterConfig对象传递进来
    • 在web.xml 中可以指定初始化参数
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>ecut.filter.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    • 访问初始化参数

        在init 方法中通过FilterConfig 对象访问

    字符集过滤器测试案例:

    package ecut.filter.filter;
    
    import java.io.IOException;
    import java.nio.charset.Charset;
    
    import javax.servlet.DispatcherType;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    
    public class CharacterEncodingFilter implements Filter{
        
        private static final String ENCODING_PARAM = "encoding" ; 
        
        private static final String DEFAULT_ENCODING = "UTF-8" ;
        
        private String encoding ;
    
        @Override
        public void init( FilterConfig filterConfig ) throws ServletException {
            System.out.println( "CharacterEncodingFilter 初始化" );
            // 获取 Filter 的初始化参数
            encoding = filterConfig.getInitParameter( ENCODING_PARAM );
            // 如果 未指定初始化参数 或 初始化参数值是 空串 则采用默认编码
            encoding = ( encoding == null || encoding.trim().isEmpty() ) ? DEFAULT_ENCODING : encoding ;
            // 如果指定的编码名称不被JVM所支持,则采用默认编码
    //        encoding = Charset.isSupported( encoding ) ? encoding : DEFAULT_ENCODING ;
            /*
            if( ! Charset.isSupported( encoding ) ) { // 如果指定的字符集名称是不支持的
                encoding = DEFAULT_ENCODING ;
            }
            */
        }
    
        @Override
        public void doFilter( ServletRequest req , ServletResponse resp , FilterChain chain )
                throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) req ;
            String uri = request.getRequestURI();
            DispatcherType type = request.getDispatcherType();
            System.out.println( "CharacterEncodingFilter ::: DispatcherType : " + type  + " , URI : " + uri  );
            // place your code here
            req.setCharacterEncoding( encoding );
            resp.setCharacterEncoding( encoding );
            // pass the request along the filter chain
            chain.doFilter( req , resp );
        }
    
        @Override
        public void destroy() {
            System.out.println( "CharacterEncodingFilter 销毁" );
        }
    
    }

    运行结果:

    解决中文乱码问题,使用过滤器后还需要 response.setContentType( "text/html" );否则仍然会乱码, 或者在响应中文中直接指定字符集response.setContentType( "text/html;charset=UTF-8" );
    6、实现对指定的调度进行过滤

    • 在web.xml 中可以指定过滤的请求REQUEST:直接访问目标资源时执行过滤器。包括:在地址栏中直接访问、表单提交、超链接、重定向,只要在地址栏中可以看到目标资源的路径,就是REQUEST;
    • FORWARD:转发访问执行过滤器。包括RequestDispatcher#forward()方法、< jsp:forward>标签都是转发访问;
    • INCLUDE:包含访问执行过滤器。包括RequestDispatcher#include()方法、< jsp:include>标签都是包含访问;
    • ERROR:当目标资源在web.xml中配置为< error-page>中时,并且真的出现了异常,转发到目标资源时,会执行过滤器。
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
    </filter-mapping>
    • 使得filter将会作用于直接从客户端过来的request,通过forward过来的request,通过include过来的request和通过<error-page>过来的request。如果没有指定任何< dispatcher >元素,默认值是REQUEST。

    测试案例:

    package ecut.filter.servlet;
    
    import java.io.IOException;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @WebServlet( "/filter/action/login" )
    public class LoginActionServlet extends HttpServlet {
    
        private static final long serialVersionUID = -7857947923197325636L;
    
        @Override
        protected void service( HttpServletRequest request, HttpServletResponse response ) 
                throws ServletException, IOException {
            
            String username = request.getParameter( "username" );
            String password = request.getParameter( "password" );
            
            System.out.println( "username : " + username +  " , password : " + password  );
            
            request.setAttribute( "username" ,  username );
            
            RequestDispatcher dispatcher = request.getRequestDispatcher( "/filter/success/login" );
            
            dispatcher.forward( request, response );
            
        }
        
        
    
    }
    package ecut.filter.servlet;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @WebServlet( "/filter/success/login" )
    public class LoginSuccessServlet extends HttpServlet {
    
        private static final long serialVersionUID = 2707448998600792264L;
    
        @Override
        protected void service( HttpServletRequest request, HttpServletResponse response ) 
                throws ServletException, IOException {
            
            //String username = (String)request.getAttribute( "username" );
            
            String username = request.getParameter( "username" );
            System.out.println( "success : " + username );
            
            response.setContentType( "text/html" );
            
            response.getWriter().println( "<h1>" + username + " </h1>" );
            
        }
    
    }
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Filter</title>
    </head>
    <body>
    
        <h5>登录</h5>
        <form action="/s/action/login" method="post" >
            <input type="text" name="username" placeholder="用户名">
            <input type="password" name="password" placeholder="输入密码">
            <input type="submit" value="登录">
        </form>
    
    </body>
    </html>

    运行结果:

    hello
    CharacterEncodingFilter ::: DispatcherType : REQUEST , URI : /s/filter/action/login
    IdentifyBrowserFilter ::: User Agent : mozilla/5.0 (windows nt 6.1; win64; x64; rv:59.0) gecko/20100101 firefox/59.0
    username : 郑 , password : 123
    CharacterEncodingFilter ::: DispatcherType : FORWARD , URI : /s/filter/success/login
    success : 郑
    world

    8、使用注解

    • Servlet 3.0 允许使用注解来标注Filter
    • @WebFilter用以标注一个实现过Filter 接口的类
    • 使用@WebFilter 标注不如web.xml 文件中可以通过映射顺序来控制过滤器的执行顺序
    • @WebFilter 的常用属性

        String filterName 指定当前Filter 的名称,相当于xml 中的filter-name
        String[] value 指定当前Filter 对应的url (与url-pattern 对应)
        String[] urlPatterns 与value 作用相同
        DispatcherType[] dispatcherTypes 指定当前Filter 关联的dispatcher 类型
          »默认值是DispatcherType.REQUEST
          »javax.servlet.DispatcherType 是Servlet 3.0 新定义的枚举
        boolean asyncSupported 指定是否支持异步操作
        WebInitParam[] initParams 用于设置Filter 初始化参数

    9、使用过滤器过滤浏览器

    测试案例:

    package ecut.filter.filter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class IdentifyBrowserFilter implements Filter {
    
        @Override
        public void init( FilterConfig config ) throws ServletException {
        }
    
        @Override
        public void doFilter( ServletRequest req , ServletResponse resp , FilterChain chain )
                throws IOException, ServletException {
            
            HttpServletRequest request = (HttpServletRequest) req ;
            HttpServletResponse response = (HttpServletResponse) resp ;
            
            String userAgent = request.getHeader( "user-agent" );
            
            userAgent = userAgent.toLowerCase();
            
            System.out.println( "IdentifyBrowserFilter ::: User Agent : " +  userAgent );
            
            // 如果在 userAgent 中找到了 trident 则说明目前正在使用 IE 访问
            if( userAgent.indexOf( "trident" ) != - 1 ) {
                String uri = request.getRequestURI();
                System.out.println( "uri : " + uri );
                int index = uri.lastIndexOf( "/" );
                uri = uri.substring( 0 , index ) ;
                System.out.println( "uri : " + uri );
                
                index = uri.lastIndexOf( "/" );
                uri = uri.substring( index ) ;
                System.out.println( "uri : " + uri );
                //解析字符串,如果访问的是IE目录下的就继续
                if( "/ie".equals( uri ) ) {
                    chain.doFilter( req , resp );
                } else {//如果访问的不是IE目录下的就重定向到ie.html
                    response.sendRedirect( request.getContextPath() +  "/pages/filter/ie/ie.html" );
                }
                
            } else { 
                // 如果是 非 IE 浏览器,则可以通过 FilterChain 向后传递 请求 和 响应 
                chain.doFilter( req , resp );
            }
            
        }
    
        @Override
        public void destroy() {
        }
    
    }
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>珍爱生命,远离IE</title>
            <link rel="stylesheet" href="/s/pages/filter/ie/ie.css" >
        </head>
        <body>
        
            <h2>珍爱生命,远离IE</h2>
            
            <h2>请使用现代浏览器: Chrome 、FireFox </h2>
            
        </body>
    </html>
    @CHARSET "UTF-8";
    
    h2 {
        text-align: center; 
    }
    
    h2:first-child {
        color: red ;
        font-weight: bold ;
    }
    
    h2:last-child {
        color: blue ;
    }

    运行结果:

    转载请于明显处标明出处

    http://www.cnblogs.com/AmyZheng/p/9024091.html

  • 相关阅读:
    响应式布局和BootStrap 全局CSS样式
    javascript中的undefined与null的区别
    before(),after(),prepend(),append()等新DOM方法简介
    解决文字和text-decoration:underline下划线重叠问题
    CSS3 linear-gradient线性渐变实现虚线等简单实用图形
    用Javascript获取页面元素的位置
    rem、px、em(手机端h5页面屏幕适配的几种方法)
    用flex和rem实现移动端页面
    HTML5新增的form属性简介(转载至张鑫旭)
    vue实现图片放大
  • 原文地址:https://www.cnblogs.com/AmyZheng/p/9024091.html
Copyright © 2011-2022 走看看