zoukankan      html  css  js  c++  java
  • Filter学习

    1.概念

            Filter也称为过滤器,通过过滤器,能够对web服务器管理的所有web资源:比如jsp、servlet、图片等进行拦截,从而实现一些特殊的功能:如实现url级别的访问控制、过滤敏感词汇、压缩响应信息等功能

                      

    2.实现

            (1)新建一个类,实现Filter接口

            (2)实现doFilter()方法

            (3)在web.xml中进行配置(类似servlet配置)

    [java] view plaincopy
     
    1. package struts;  
    2.   
    3. import java.io.IOException;  
    4. import javax.servlet.Filter;  
    5. import javax.servlet.FilterChain;  
    6. import javax.servlet.FilterConfig;  
    7. import javax.servlet.ServletException;  
    8. import javax.servlet.ServletRequest;  
    9. import javax.servlet.ServletResponse;  
    10.   
    11. /** 
    12.  * Servlet Filter implementation class FirstFilter 
    13.  */  
    14. public class FirstFilter implements Filter  
    15. {  
    16.     private FilterConfig filterConfig;  
    17.       
    18.     public FirstFilter()   
    19.     {  
    20.     }  
    21.   
    22.     public void destroy()   
    23.     {  
    24.         System.out.println("销毁Filter");  
    25.     }  
    26.   
    27.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException   
    28.     {  
    29.         System.out.println("过滤前");  
    30.         System.out.println(filterConfig.getInitParameter("initParam"));  
    31.         chain.doFilter(request, response);  
    32.         System.out.println("过滤后");  
    33.     }  
    34.   
    35.     public void init(FilterConfig fConfig) throws ServletException   
    36.     {  
    37.         System.out.println("初始化Filter");  
    38.         filterConfig = fConfig;  
    39.     }  
    40.   
    41. }  

               web.xml中配置

    [html] view plaincopy
     
    1. <filter>  
    2.     <filter-name>Demo1Filter</filter-name>  
    3.     <filter-class>struts.FirstFilter</filter-class>  
    4.     <init-param>  
    5.         <param-name>initParam</param-name>  
    6.         <param-value>value在这里呢</param-value>  
    7.     </init-param>  
    8. </filter>  
    9. <filter-mapping>  
    10.     <filter-name>Demo1Filter</filter-name>  
    11.     <url-pattern>/*</url-pattern>  
    12.     <dispatcher>REQUEST</dispatcher<!-- 没有配置dispatcher就是默认request方式的 -->  
    13.     <dispatcher>FORWARD</dispatcher>  
    14.     <dispatcher>ERROR</dispatcher>  
    15.     <dispatcher>INCLUDE</dispatcher>  
    16. </filter-mapping>  

     

    3.应用场景

            (1)通过控制是否对chain.doFilter的方法调用,来决定是否需要访问目标资源

                       比如:可以用在用户权限验证。判断用户是否有访问某些资源的权限,如果有权限就放行,没有则不执行chain.doFilter方法

            (2)通过在调用chain.doFilter之前,来做一些处理

                       比如,解决中文乱码问题。在doFilter方法之前,执行设置请求编码与响应编码。

            (3)通过在调用chain.doFilter之后,来做一些处理

                       比如,对整个网站进行压缩

     

    4.Filter拦截原理

          Filter接口中有一个doFilter方法,当开发人员实现了Filter中的doFilter后,并配置对哪个web资源进行拦截后,web服务器每次在调用web资源之前,都会先调用一下Filter的doFilter方法       

    5.Filter生命周期

          Filter和Servlet一样,创建和销毁都是由web容器来负责的。和Servlet不同的是:

          (1)在应用启动的时候就装载Filter类(与Servlet的load-on-startup配置效果相同)

          (2)容器创建好Filter对象实例之后,负责调用init()方法。然后保存在Web容器中,等待用户访问资源

          (3)当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter实例调用doFilter方法

          (4)当应用停止时,会调用Filter的destory方法,Filter对象销毁

    5.Filter部署注意事项

          (1)filter-mapping标签中的servlet-name与url-pattern

                    Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet

          (2)filter-mapping标签中的dispatcher

                    指定过滤器所拦截的资源被Servlet容器调用的方式,可以是REQUEST、INCLUDE、FORWARD和ERROR之一,默认是REQUEST,可以指定多个

                    REQUEST:

                     当用户直接访问页面时,web容器将会调用过滤器,如果是通过RequestDispatcher的include或者forward方法或者ERROR情况时,该过滤器就不会被调用

                   INCLUDE:

                     如果通过RequestDispatcher的include方法访问时,这个过滤器将被调用

                   FORWARD:

                     如果通过RequestDispatcher的forward方法访问时,这个过滤器将被调用

                   ERROR:

                     如果在A.jsp的page指令中指定了error属性=error.jsp,那么如果A.jsp中出现了异常,就会跳转到error.jsp中处理,而在跳转到error.jsp时,如果过滤器配置了ERROR的dispatcher,那么则会拦截

          (3)执行顺序

                   1)先执行带有rul-pattern标签的filter,再执行带有servlet-name标签的filter,两种标签写法如下:

    [html] view plaincopy
     
    1. <filter-mapping>  
    2.    <filter-name>BeerRequest1</filter-name>  
    3.    <url-pattern>*.do</url-pattern>  
    4. </filter-mapping>  
    5.   
    6. <filter-mapping>  
    7.    <filter-name>BeerRequest2</filter-name>  
    8.    <servlet-name>AdviceServlet</servlet-name>  
    9. </filter-mapping>  

                   2)如果同为url-pattern或者servlet0name,则会按照在web.xml中的声明顺序执行

          (4)匹配多个url-pattern

    [html] view plaincopy
     
      1. <filter>  
      2.     <filter-name>authority</filter-name>  
      3.     <filter-class>com.util.AuthorityFilter</filter-class>  
      4. </filter>  
      5. <filter-mapping>  
      6.     <filter-name>authority</filter-name>  
      7.        <url-pattern>/pages/genbill/*</url-pattern>  
      8. </filter-mapping>  
      9. <filter-mapping>  
      10.     <filter-name>authority</filter-name>  
      11.     <url-pattern>/pages/cmm/*</url-pattern>  
      12. </filter-mapping>  

    java web filter 之一 基础实现

    本文主要对filter的基本使用进行了讲解,其中涉及到了

          filter是什么

          一个filter处理一个jsp

          多个filter处理一个jsp

    filter是什么

           Filter 是java下的一种过滤器 ,能实现对java web程序 客户端和服务器端消息的过滤,也就是在服务器段接受request之前,可以预先对request进行处理,或在客户端接受response之前,对response进行处理。

           Filter的使用非常灵活,是在“链”到客户端和服务器之间的,在需要时可以配置到客户端与服务器之间,在不需要时可以去掉。filter还可以设置其对发送到哪些页面或从哪些页面发出的消息进行过滤,即是一中横切性的编程,可插拔。Filter执行的大致过程如下图

           实现filter相关的功能,需要实现javax.servlet.jar包下的filter接口,该接口有三个方法,分别是init doFilter,destory方法,把需要执行某些功能的代码放到doFilter方法中

    一个Filter处理一个jsp:

    实现filter要实现javax.servlet包下的filter接口,本例子实现的是设置所有jsp也的字符编码

    package com.tgb.drp.util.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;
    
    /**
     * 采用filter统一处理字符集
     *
     */
    public class CharsetEncodingFilter implements Filter {
    	
    	private String encodeString;
            //Filter注销方法
    	@Override
    	public void destroy() {
    	
    
    	}
            //filter要实现的功能
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response,
    			FilterChain chain) throws IOException, ServletException {
    		System.out.println("begin");
    		// 设置字符集
    		request.setCharacterEncoding(encodeString);
    		
    		//继续向下执行,如果还有其他filter继续调用其他filter,没有的话将消息发送给服务器或客户端
    		chain.doFilter(request, response);
    		System.out.println("end");
    	}
            //初始化方法
    	@Override
    	public void init(FilterConfig filterConfig) throws ServletException {
    		//
    		encodeString=filterConfig.getInitParameter("encoding");
    	}
    
    }
     
    
    //写好filter类后,需要在配置文件中设置对哪些request和response进行过滤处理,本例子设置对所有的jsp页进行处理,在web.xml的web-app节点下,配置好后,可以写一个jsp页进行测试了。
    
     
    
        <filter>
        	<filter-name>CharsetEncodingFilter</filter-name>
        	<filter-class>com.tgb.drp.util.filter.CharsetEncodingFilter</filter-class>
        	<init-param>
        		<param-name>encoding</param-name>
        		<param-value>GBK</param-value>
        	</init-param>
        </filter>
        <filter-mapping>
        	<filter-name>CharsetEncodingFilter</filter-name>
        	<url-pattern>*.jsp</url-pattern>
        </filter-mapping>
    

      

     

    多个filter处理一个jsp页

           如果想实现多个filter对同一个jsp页进行处理,例如既需要设置字符编码,又需要验证身份,只需要在在写好响应的filter后继续配置在web.xml里。我们继续上面的例子,再写一个验证身份的Filter,命名为AuthenticationFilter,代码如下

    package com.tgb.drp.util.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;
    import javax.servlet.http.HttpSession;
    
    
    public class AuthenticationFilter implements Filter {
    
    	@Override
    	public void destroy() {
    
    	}
    
    	@Override
    	public void doFilter(ServletRequest request, ServletResponse response,
    			FilterChain chain) throws IOException, ServletException {
    		//控制用户访问权限
    		HttpServletRequest req=(HttpServletRequest)request;
    		HttpServletResponse res=(HttpServletResponse)response;
    		HttpSession session=req.getSession();
    
    		if(session.getAttribute("user_info")!=null){
    			chain.doFilter(request, response);
    		}else{
    			res.sendRedirect(req.getContextPath()+"/error.html");
    		}
    	}
    
    	@Override
    	public void init(FilterConfig filterConfig) throws ServletException {
    	
    
    	}
    
    }


    然后在配置文件里继续进行下配置,代码如下

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" 
    	xmlns="http://java.sun.com/xml/ns/j2ee" 
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
      	<welcome-file-list>
            <welcome-file>index.html</welcome-file>
    
        </welcome-file-list> 
        <filter>
        	<filter-name>CharsetEncodingFilter</filter-name>
        	<filter-class>com.tgb.drp.util.filter.CharsetEncodingFilter</filter-class>
        	<init-param>
        		<param-name>encoding</param-name>
        		<param-value>GBK</param-value>
        	</init-param>
        </filter>
        <filter-mapping>
        	<filter-name>CharsetEncodingFilter</filter-name>
        	<url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        
        <filter>
        	<filter-name>AuthenticationFilter</filter-name>
        	<filter-class>com.tgb.drp.util.filter.AuthenticationFilter</filter-class>
        </filter>
        <filter-mapping>
        	<filter-name>AuthenticationFilter</filter-name>
        	<url-pattern>*.jsp</url-pattern>
        </filter-mapping>
    	
    	<session-config>
    		<session-timeout>60</session-timeout>
    	</session-config>
    </web-app>
    

      好了到此就可以设置两个filter对一个jsp页进行处理了,当启动tomcat,访问响应的jsp页时,设置的filter就会起作用。

    6.1. Filter

    6.1.1. Filter的用途

    Filter这种机制常被用来实现下面的功能:

    页面授权 根据登录用户的权限,阻止或许可用户访问特定的页面。
    日志和审计 记录和检查用户访问WEB应用的情况。
    图片转换 改变图片的格式、精度、尺寸等。
    页面压缩 压缩页面内容,加快下载速度。
    本地化 显示本地语言和风格的页面。
    XSLT转换 对XML内容进行XSLT转换,使之适用于多种客户端。
    高速缓存 高速缓存页面,提高响应速度。

    当然还有更多种的应用,我们不可能一一列举。

    Filter的通用性很好。任何filter均独立于其它filter和servlet,因此它可以和任意其它filter和servlet组合搭配。下面是一段配置示例 ── 通过SetLoggingContextFilter,日志系统可以记录当前请求的信息,例如:URL、referrer URL、query string等。

    例 6.1. Filter配置示例(/WEB-INF/web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://java.sun.com/xml/ns/j2ee  http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd
        ">
        <filter>
            <filter-name>mdc</filter-name>
            <filter-class>com.alibaba.citrus.webx.servlet.SetLoggingContextFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>mdc</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        ...
    </web-app>

    6.1.2. Filter工作原理

    Filter Chain

    图 6.1. Filter Chain

    如图所示。多个filter和至多一个servlet被串联成一个链,被称为Filter Chain。执行的时候,引擎将控制权交给链条中的头一个filter(如果有的话)。然后,就像击鼓传花一样,控制权被依次传递给filter chain中的下一个filter或servlet。每一个得到控制权的filter可以做下面的事:

    • 继续传递控制权或立即终止filter chain。

      • Filter可将控制权传递给链条中的下一个filter或者最终的servlet。

      • Filter也可以不将控制权传递给下一个filter或servlet,这样便中止了整个filter chain的执行。

    • 预处理。在传递控制权给下一个filter或servlet之前,filter可以预先做一些事情:

      • 设置request、response中的参数,例如:character encoding、content type等。

      • HttpServletRequestWrapper传递给链条中的下一位,filter可以通过wrapper改变request中的任意值。

      • HttpServletResponseWrapper传递给链条中的下一位,filter可以通过wrapper来拦截后续filter或servlet对response的修改。

    • 提交。在控制权从filter chain中返回以后,filter还可以做一些后续提交的操作。

      • 例如,将response中拦截而来的数据,压缩或转换格式,并发送给客户端或filter chain的上一级。

      • 通过trycatch还可以捕获filter chain下一级所有的异常,并做处理。

    6.1.3. Filter的限制

    Filter是很有用的。作为servlet的补充,filter也是很成功的。但是filter并没有被设计用来完成一切事情。事实上,filter的设计限制了filter的用途。每个filter具有下面的限制:

    • Filter可以访问和修改数据。但它只能访问和修改HttpServletRequestHttpServletResponseServletContext等容器级的对象,而不能(或很难)访问应用程序中的状态。所以filter无法实现和应用逻辑密切相关的功能。

    • Filter可以影响执行流程。但它不能改变filter chain的结构和顺序。Filter chain的结构和顺序是由web.xml中定义的。当filter得到控制权以后,它只能选择继续下去,或者立即结束,而没法进行循环、分支、条件判断等更复杂的控制。因此,filter只能用来实现粗粒度的流程控制功能(例如,当用户未获授权时,停止执行filter chain),难以应付更细致的应用程序内的控制需求。

    • Filter与其它filter和servlet之间,除了request和response对象以外,无法共享其它的状态。这既是优点又是缺点。优点是使filter更独立、更通用;缺点是filter与其它filter、servlet之间难以协作,有时甚至会引起无谓的性能损失。

    6.1.4. Webx对filter功能的补充

    综上所述,一个filter常常做的两件事是:

    • 改变request/response对象(通过HttpServletRequestWrapperHttpServletResponseWrapper);

    • 改变应用执行的流程。

    其实,大部分filter只做其中一件事。例如:

    • 页面压缩filter仅仅改变response,并不改变应用的流程。

    • 页面授权filter根据当前请求用户的身份,判定他是否有权限访问当前页面。这个filter会影响应用流程,却不会去改变request和response。

    当然也有例外。有一些filter不做上面两件事中任何一件。例如,日志filter仅仅读取request对象并记录日志而已,既不改变request/response,也不影响应用的流程。还有一些filter同时做上面两件事。比如高速缓存页面的filter不仅要修改response,而且当cache被命中时,不再执行下一步的流程,而是直接返回cache中的内容,以提高性能。

    Webx框架提供了两个服务,正好吻合了上述两个最常用的filter的功能。

    Request Contexts服务 该服务负责访问和修改request和response,但不负责改变应用执行的流程。
    Pipeline服务 提供应用执行的流程,但不关心request和response。

    虽然这两个服务看起来和filter的功能类似,但是它们远比filter要强大和方便 ── 它们克服了上述filter的几个限制:

    • 和Filter不同,Request Contexts和Pipeline服务可以访问应用内部的状态和资源,效率更高,功能更强。

    • 和Filter不同,Pipeline服务可以定义灵活(但仍然简单)地控制应用的流程 。Pipeline不仅可以控制流程的中断或继续,还可以实现子流程、循环、条件转移、异常处理等更精细的流程控制。Pipeline服务甚至可以运用在非WEB的环境中。

    • 和Filter不同,Request Contexts服务中的每一个环节(Request Context)之间并非完全独立、互不干涉的。每个request context可以访问它所依赖的其它request context中的状态。

  • 相关阅读:
    阶段1 语言基础+高级_1-3-Java语言高级_04-集合_03 斗地主案例(单列)_2_斗地主案例的代码实现
    阶段1 语言基础+高级_1-3-Java语言高级_04-集合_03 斗地主案例(单列)_1_斗地主案例的需求分析
    阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_6_泛型通配符
    阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_5_定义和使用含有泛型的接口
    阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_4_定义和使用含有泛型的方法
    阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_3_定义和使用含有泛型的类
    阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_2_使用泛型的好处
    阶段1 语言基础+高级_1-3-Java语言高级_04-集合_02 泛型_1_泛型的概念
    为什么企业编写代码时禁止使用制表符
    header('Location:'.C('VIP_HX').'/CmdId/'.$CmdId.'/user_id/'.$user_id.'/Token/'.$Token);
  • 原文地址:https://www.cnblogs.com/Vae1990Silence/p/4624990.html
Copyright © 2011-2022 走看看