servlet过滤器

来源:互联网 发布:如何使用网络代理 编辑:程序博客网 时间:2024/05/18 00:16

一、概念:

      Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能

Java Web 之过滤器Filter详解

二、Filter简介

        Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。

三、快速入门

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

2、实现doFilter()方法,打印一句话,来证明能够进行拦截

3、在web.xml中进行配置(参照Servlet配置)

4、访问一个页面,看看能不能拦截

[java] view plain copy
  1. package com.test.filter;    
  2.   
  3.      
  4.   
  5. import java.io.IOException;    
  6.   
  7. import javax.servlet.Filter;    
  8.   
  9. import javax.servlet.FilterChain;    
  10.   
  11. import javax.servlet.FilterConfig;    
  12.   
  13. import javax.servlet.ServletException;    
  14.   
  15. import javax.servlet.ServletRequest;    
  16.   
  17. import javax.servlet.ServletResponse;    
  18.   
  19. public class Demo1Filter implements Filter {    
  20.   
  21.     private FilterConfig filterConfig;    
  22.   
  23.      
  24.   
  25.     public void doFilter(ServletRequest request, ServletResponse response,    
  26.   
  27.             FilterChain chain) throws IOException, ServletException {    
  28.   
  29.         System.out.println("Demo1过滤前");    
  30.   
  31.         System.out.println(filterConfig.getInitParameter("param1"));    
  32.   
  33.         chain.doFilter(request, response);//放行。让其走到下个链或目标资源中    
  34.   
  35.         System.out.println("Demo1过滤后");    
  36.   
  37.     }    
  38.   
  39.      
  40.   
  41.     public void init(FilterConfig filterConfig) throws ServletException {    
  42.   
  43.         System.out.println("初始化了");    
  44.   
  45.         this.filterConfig = filterConfig;    
  46.   
  47.     }    
  48.   
  49.      
  50.   
  51.     public void destroy() {    
  52.   
  53.         System.out.println("销毁了");    
  54.   
  55.     }    
  56.   
  57. }   


web.xml中进行配置

[html] view plain copy
  1. <filter>  
  2.     <filter-name>Demo1Filter</filter-name>  
  3.     <filter-class>com.itheima.filter.Demo1Filter</filter-class>  
  4.     <init-param>  
  5.         <param-name>param1</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>  


 

四、Filter的应用场景

通过对filter过滤器的了解,可以得知在以下三种情况下可以做些处理:

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

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

2> 通过在调用chain.doFilter方法之前,做些处理来达到某些目的。

比如,解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)

3> 通过在调用chain.doFilter方法之后,做些处理来达到某些目的。

比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类Aresponse对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类AByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。

五、Filter实现拦截的原理

Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filterdoFilter方法

六、Filter生命周期

Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是,它是1>在应用启动的时候就进行装载Filter(Servletload-on-startup配置效果相同)2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。3>当用户访问的资源正好被Filterurl-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)4>应用服务被停止或重新装载了,则会执行Filterdestroy方法,Filter对象销毁。

注意:init方法与destroy方法只会直接一次。

七、Filter部署应用注意事项

1> filter-mapping标签中servlet-nameurl-pattern

Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet(专门为某个servlet服务了,servlet-name对应Servlet的相关配置)

2> filter-mapping标签中dispatcher

指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARDERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。

REQUEST

当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcherinclude()forward()方法访问或ERROR情况时,那么该过滤器就不会被调用。

INCLUDE

如果目标资源是通过RequestDispatcherinclude()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

FORWARD

如果目标资源是通过RequestDispatcherforward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。

ERROR

如若在A.jsp页面page指令中指定了error属性=examError.jsp,那么A.jsp中若出现了异常,会跳转到examError.jsp中处理。而在跳转到examError.jsp时,若过滤器配置了ERRORdispather那么则会拦截,否则不会拦截。


总结:

一个filter 包括:

  1. 在servlet被调用之前截获;

  2. 在servlet被调用之前检查servlet request;

  3. 根据需要修改request头和request数据;

  4. 根据需要修改response头和response数据;

  5. 在servlet被调用之后截获.

  你能够配置一个filter 到一个或多个servlet;单个servlet或servlet组能够被多个filter 使用.几个实用的filter 包括:用户辨认filter,日志filter,审核filter,加密filter,符号filter,能改变xml内容的XSLT filter等.


filter作用及原理上面其实已经讲得差不多(要我写还写不出来这么高大上的东西),那么我附上一个简单而实用的代码,


  1. <!-- 自定义的过滤器  -->  
  2.     <filter>  
  3.         <filter-name>authorityFilter</filter-name>  <span style="font-family: Arial, Helvetica, sans-serif;">         </span>  
  4.         <filter-class>cn.thinknet.filter.AuthorityFilter</filter-class><span style="font-family: Arial, Helvetica, sans-serif;"><!-- 自定义过滤器的位置 --></span>  
  5.   
  6.         <init-param>  
  7.             <param-name>allowAuthorityURL</param-name><!-- 不需要过滤的地址 -->  
  8.             <param-value>login.jsp,register.jsp,login.action,sendMail.action,register.action,getbackPwdOne.jsp,getbackPwdTwo.jsp,getbackPwdThree.jsp,getbackOne.action,getbackTwo.action,getbackThree.action,forget_pwd.action,getHomePageResult.action,index.jsp,index.html,userAuthen.action</param-value>  
  9.         </init-param>  
  10.           
  11.         <init-param>  
  12.             <param-name>authorityURL</param-name><!-- 只对指定过滤参数后缀进行过滤 -->  
  13.             <param-value>.action,.jsp,.do</param-value>  
  14.         </init-param>  
  15.         <init-param>  
  16.             <param-name>redirectPath</param-name><!-- 未通过跳转到登录界面 -->  
  17.             <param-value>/wrtPlatformVt/wrt/login.jsp</param-value>  
  18.         </init-param>  
  19.         <init-param>  
  20.             <param-name>disableFilter</param-name><!-- Y:过滤无效 -->  
  21.             <param-value>N</param-value>  
  22.         </init-param>  
  23.     </filter>  
  24.       
  25.     <filter-mapping> <!-- 拦截所有的请求信息   如想通过扩展名匹配拦截。 如:.action后缀的请求 配置则为 *.action-->  
  26.                      <!-- 精确匹配  顾名思义精确到单个请求  如:/manage/login.action 配置则为/manage/login.action -->  
  27.                      <!-- 路劲匹配  通过*配符的方式进行相对匹配,如下的/* 则表示拦截所有信息 -->  
  28.         <filter-name>authorityFilter</filter-name>  
  29.         <url-pattern>/*</url-pattern>  
  30.     </filter-mapping>


<init-param> 标签对应的是参数名和值,可以用于在init()时通过FilterConfig的对象 filterConfig.getInitParameter("参数名")获取。


自定义过滤器代码:


  1. package cn.thinknet.filter;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PrintWriter;  
  5. import javax.servlet.Filter;  
  6. import javax.servlet.FilterChain;  
  7. import javax.servlet.FilterConfig;  
  8. import javax.servlet.ServletException;  
  9. import javax.servlet.ServletRequest;  
  10. import javax.servlet.ServletResponse;  
  11. import javax.servlet.http.Cookie;  
  12. import javax.servlet.http.HttpServlet;  
  13. import javax.servlet.http.HttpServletRequest;  
  14.   
  15. import org.apache.commons.lang3.ArrayUtils;  
  16. import org.apache.commons.lang3.StringUtils;  
  17.   
  18. import cn.thinknet.utils.others.AKKeysUtil;  
  19.   
  20.   
  21. /** 
  22.  * 过滤器 
  23.  *  
  24.  *  
  25.  *  
  26.  */  
  27. public class AuthorityFilter extends HttpServlet implements Filter  
  28. {  
  29.     /** 
  30.      *  
  31.      */  
  32.     private static final long serialVersionUID = 4504557649329493897L;  
  33.   
  34.     public String[] allowAuthorityURLs;  
  35.   
  36.     public String[] authorityURLs;  
  37.   
  38.     public FilterConfig config;  
  39.       
  40.     /** 
  41.      * 过滤不能访问的地址 
  42.      */  
  43.     @Override  
  44.     public void doFilter(ServletRequest request, ServletResponse response,  
  45.             FilterChain filterChain) throws IOException, ServletException  
  46.     {  
  47.         // 未登录需要跳转的地址  
  48.         String redirectPath = config  
  49.                 .getInitParameter(AKKeysUtil.WEB_CONTEXT_REDIRECT_PATH);  
  50.   
  51.         // 过滤是否启用  
  52.         boolean isEnable = true// 过滤器可用  
  53.         String disableStr = config  
  54.                 .getInitParameter(AKKeysUtil.WEB_CONTEXT_DISABLE_FILTER);  
  55.         if (StringUtils.isNotEmpty(disableStr))  
  56.         {  
  57.             isEnable = disableStr.equals("N");  
  58.         }  
  59.         HttpServletRequest req = (HttpServletRequest) request;  
  60.           
  61.         // 判断过滤器是否启用  
  62.         if (!isEnable)  
  63.         {  
  64.             filterChain.doFilter(request, response);  
  65.             return;  
  66.         }  
  67.           
  68.         // 需要过滤的后缀  
  69.         String authorityURL = config  
  70.                 .getInitParameter(AKKeysUtil.WEB_CONTEXT_AUTHORITY_URL);  
  71.         if (StringUtils.isNotEmpty(authorityURL))  
  72.         {  
  73.             authorityURLs = authorityURL.split(",");  
  74.         }  
  75.   
  76.         // 判断当前的请求地址中是否存在需要过滤的后缀  
  77.         if (authorityURL(req))  
  78.         {  
  79.             // 不需要过滤的地址  
  80.             String allowAuthorityURL = config  
  81.                     .getInitParameter(AKKeysUtil.WEB_CONTEXT_ALLOW_AUTHORITY_URL);  
  82.             if (StringUtils.isNotEmpty(allowAuthorityURL))  
  83.             {  
  84.                 allowAuthorityURLs = allowAuthorityURL.split(",");  
  85.             }  
  86.   
  87.             // 过滤不拦截的url  
  88.             if (allowAuthorityURL(req))  
  89.             {  
  90.                 filterChain.doFilter(request, response);  
  91.                 return;  
  92.             } else  
  93.             {  
  94.                 // 判断当前用户是否登录,没有登录直接跳转到登录页面  
  95.                 if (!relogin(redirectPath, response, req))  
  96.                 {  
  97.                     return;  
  98.                 }  
  99.             }  
  100.               
  101.             // 最后对action与jsp进行权限校验  
  102.             // if (authorityRequestAddress(req))  
  103.             // {  
  104.             // 【暂时不实现纵向越权控制】  
  105.             filterChain.doFilter(request, response);  
  106.             // }  
  107.             // else  
  108.             // {  
  109.             // 没有权限时  
  110.             // noAuthority();  
  111.             // }  
  112.         } else  
  113.         {  
  114.             // 例如js,image,css等文件不列入权限控制范围内  
  115.             filterChain.doFilter(request, response);  
  116.         }  
  117.     }  
  118.   
  119.     @Override  
  120.     public void init(FilterConfig filterConfig) throws ServletException  
  121.     {  
  122.         config = filterConfig;  
  123.         // WebApplicationContext ctx = WebApplicationContextUtils  
  124.         // .getWebApplicationContext(this.getServletContext());  
  125.   
  126.         // menuService = (MenuService) ctx.getBean("menuService");  
  127.     }  
  128.   
  129.     /** 
  130.      * 在未登陆的情况下允许访问的URL 
  131.      *  
  132.      * @return Boolean 
  133.      */  
  134.     private boolean allowAuthorityURL(HttpServletRequest request)  
  135.     {  
  136.         boolean isAllow = false;  
  137.         // 获得当前访问的地址  
  138.         String current_url = request.getRequestURI();  
  139.   
  140.         if (ArrayUtils.isNotEmpty(allowAuthorityURLs))  
  141.         {  
  142.             for (String allowUrl : allowAuthorityURLs)  
  143.             {  
  144.                 if (StringUtils.containsIgnoreCase(current_url, allowUrl))  
  145.                 {  
  146.                     isAllow = true;  
  147.                     break;  
  148.                 }  
  149.             }  
  150.         }  
  151.         return isAllow;  
  152.     }  
  153.   
  154.     /** 
  155.      * 需要过滤的后缀 
  156.      *  
  157.      * @return Boolean 
  158.      */  
  159.     private boolean authorityURL(HttpServletRequest request)  
  160.     {  
  161.         boolean isFilter = false;  
  162.         if (ArrayUtils.isNotEmpty(authorityURLs))  
  163.         {  
  164.             for (String suffix : authorityURLs)  
  165.             {  
  166.                 if (request.getRequestURI().indexOf(suffix) != -1)  
  167.                 {  
  168.                     isFilter = true;  
  169.                     break;  
  170.                 }  
  171.             }  
  172.         }  
  173.         return isFilter;  
  174.     }  
  175.   
  176.     /** 
  177.      * 判断员工回话是否失效 
  178.      *  
  179.      * @param redirectPath 
  180.      *            需要跳转的页面 
  181.      * @param response 
  182.      *            请求响应 
  183.      *  
  184.      * @param request 
  185.      *            请求 
  186.      *  
  187.      * @throws IOException 
  188.      *  
  189.      * @return boolean 假:代表重新登录,真:代表session存在 
  190.      */  
  191.     private boolean relogin(String redirectPath, ServletResponse response,  
  192.             HttpServletRequest request) throws IOException  
  193.     {  
  194.         response.setContentType("text/html;charset=UTF-8");  
  195.         response.setCharacterEncoding("UTF-8");  
  196.         PrintWriter out = response.getWriter();  
  197.         // 判断该用户是否存在session中,如果有直接进入当前action  
  198.         if (null == request.getSession(true).getAttribute(  
  199.                 AKKeysUtil.USER_EMPLOY_SESSION_KEY))  
  200.         {  
  201.             // 跳转到登录界面  
  202.             out.print("<script language='javascript'>alert('身份验证失效,请重新登录!');window.parent.location.href='"  
  203.                     + redirectPath + "';</script>");  
  204.             return false;  
  205.         }  
  206.   
  207.         // 如果用户禁用掉cookie,则跳转到登录界面,提示用户启用cookie  
  208.         Cookie[] cookies = request.getCookies();  
  209.         if (null == cookies)  
  210.         {  
  211.             // 1.可能用户清除过cookie 2.可能是由于用户禁用了cookie 此时都会跳转到登录界面  
  212.             // 跳转到登录界面  
  213.             out.print("<script language='javascript'>alert('Cookie被清理或是已禁用,请尝试重新登录!');window.parent.location.href='"  
  214.                     + redirectPath + "';</script>");  
  215.             return false;  
  216.         }  
  217.         return true;  
  218.     }  
  219. }  

注意,AKKeysUtil这个是封装好的一个工具类,所有使用到的地方对应的均是 <init-param>标签的参数名,自行对应更改即可。
0 0
原创粉丝点击