• Java过滤器详细文档,简介,实例,应用


    简介

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

    Filter技术是servlet 2.3新增加的功能。它能够对Servlet容器的请求和响应对象进行检查和修改。

    Filter本身并不生成请求和响应对象,只是提供过滤功能

    Filter能够在Servlet被调用之前检查Request对象,并修改Request Header和Request内容;在Servlet被调用之后检查Response对象,修改Response Header和Response的内容。

    Filter可以过滤的Web组件包括Servlet,JSP和HTML等文件。

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

    2.Filter的工作原理

       当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行拦截,对请求头和请求数据进行检查或改动,并依次通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据条件让请求不发往资源处理器,并直接向客户机发回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务。

       两个过滤器同时过滤一个请求时,就要用到过滤链FilterChain。Filter的FilterChain中,服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。执行的顺序就如下图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的chain.doFilter()之后的代码,最后返回响应。

     

            Filter的执行流程就是:

    执行第一个过滤器的chain.doFilter()之前的代码——

    >第二个过滤器的chain.doFilter()之前的代码——>……——

    >第n个过滤器的chain.doFilter()之前的代码——

    >所请求servlet的service()方法中的代码——>

    所请求servlet的doGet()或doPost()方法中的代码——

    >第n个过滤器的chain.doFilter()之后的代码——>……——

    >第二个过滤器的chain.doFilter()之后的代码——

    >第一个过滤器的chain.doFilter()之后的代码。

    3、Filter生命周期

         1> Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是,它是1>在应用启动的时候就进行装载Filter类(与Servlet的load-on-startup配置效果相同)。

         2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。

         3>当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)。

         4>当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。

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

    也可以简单理解:

    1)实例化:Web容器在部署Web应用程序时对所有过滤器进行实例化。Web容器回调它的无参构造方法。

    2)初始化:实例化完成之后,马上进行初始化工作。Web容器回调init()方法。

    3)过滤:请求路径匹配过滤器的URL映射时。Web容器回调doFilter()方法——主要的工作方法。

    4)销毁: Web容器在卸载Web应用程序前,Web容器回调destroy()方法。

    4,Filter的部署

    分为两个步骤:

      1、注册Filter

            <description>用于添加描述信息,该元素的内容可为空,<description>可以不配置。

      <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。

      <filter-class>元素用于指定过滤器的完整的限定类名。

      <init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。如果过滤器不需要指定初始化参数,那么<init-param>元素可以不配置。

     

      2、映射Filter

    web.xml文件中注册了Filter之后,还要在web.xml文件中映射Filter

     <!--映射过滤器-->

        <filter-mapping>

           <filter-name>FilterDemo02</filter-name>

             <!--“/*”表示拦截所有的请求 -->

             <url-pattern>/*</url-pattern>

        </filter-mapping>

    <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 对资源的多种调用方式进行拦截。如下:

          <filter-mapping>

                     <filter-name>testFilter</filter-name>

                           <url-pattern>/index.jsp</url-pattern>

                           <dispatcher>REQUEST</dispatcher>

                          <dispatcher>FORWARD</dispatcher>

             </filter-mapping>

      <dispatcher> 子元素可以设置的值及其意义:

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

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

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

     ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

    Filter开发步骤

      Filter开发分为二个步骤:

     编写java类实现Filter接口,并实现其doFilter方法。

      web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。

     

     <!-- 自定义的过滤器  -->  

         <filter>  

             <filter-name>authorityFilter</filter-name>  <span style="font-family: Arial, Helvetica, sans-serif;">         </span>  

             <filter-class>cn.thinknet.filter.AuthorityFilter</filter-class><span style="font-family: Arial, Helvetica, sans-serif;"><!-- 自定义过滤器的位置 --></span>  

       

             <init-param>  

                 <param-name>allowAuthorityURL</param-name><!-- 不需要过滤的地址 -->  

                 <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>  

             </init-param>  

               

             <init-param>  

                 <param-name>authorityURL</param-name><!-- 只对指定过滤参数后缀进行过滤 -->  

                 <param-value>.action,.jsp,.do</param-value>  

             </init-param>  

             <init-param>  

                 <param-name>redirectPath</param-name><!-- 未通过跳转到登录界面 -->  

                 <param-value>/wrtPlatformVt/wrt/login.jsp</param-value>  

             </init-param>  

             <init-param>  

                 <param-name>disableFilter</param-name><!-- Y:过滤无效 -->  

                 <param-value>N</param-value>  

             </init-param>  

         </filter>  

           

         <filter-mapping> <!-- 拦截所有的请求信息   如想通过扩展名匹配拦截。 如:.action后缀的请求 配置则为 *.action-->  

                          <!-- 精确匹配  顾名思义精确到单个请求  如:/manage/login.action 配置则为/manage/login.action -->  

                          <!-- 路劲匹配  通过*配符的方式进行相对匹配,如下的/* 则表示拦截所有信息 -->  

             <filter-name>authorityFilter</filter-name>  

             <url-pattern>/*</url-pattern>  

         </filter-mapping>  

    附上:servlet url-pattern匹配规则:http://zy19982004.iteye.com/blog/1751695

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

    附上:<init-param>标签的基本使用:http://blog.csdn.net/yakson/article/details/9203231

    自定义过滤器代码:

    [java] view plain copy

     package cn.thinknet.filter;  

     import java.io.IOException;  

     import java.io.PrintWriter;  

     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.Cookie;  

     import javax.servlet.http.HttpServlet;  

     import javax.servlet.http.HttpServletRequest;  

     import org.apache.commons.lang3.ArrayUtils;  

     import org.apache.commons.lang3.StringUtils;  

     import cn.thinknet.utils.others.AKKeysUtil;  

     /** 

      * 过滤器 

      *  

      *  

      *  

      */  

     public class AuthorityFilter extends HttpServlet implements Filter  

     {  

         private static final long serialVersionUID = 4504557649329493897L;  

         public String[] allowAuthorityURLs;  

         public String[] authorityURLs;  

         public FilterConfig config;  

           

         /** 

          * 过滤不能访问的地址 

          */  

         @Override  

         public void doFilter(ServletRequest request, ServletResponse response,  

                 FilterChain filterChain) throws IOException, ServletException  

         {  

             // 未登录需要跳转的地址  

             String redirectPath = config  

                     .getInitParameter(AKKeysUtil.WEB_CONTEXT_REDIRECT_PATH);  

       

             // 过滤是否启用  

             boolean isEnable = true; // 过滤器可用  

             String disableStr = config  

                     .getInitParameter(AKKeysUtil.WEB_CONTEXT_DISABLE_FILTER);  

             if (StringUtils.isNotEmpty(disableStr))  

             {  

                 isEnable = disableStr.equals("N");  

             }  

             HttpServletRequest req = (HttpServletRequest) request;  

               

             // 判断过滤器是否启用  

             if (!isEnable)  

             {  

                 filterChain.doFilter(request, response);  

                 return;  

             }  

               

             // 需要过滤的后缀  

             String authorityURL = config  

                     .getInitParameter(AKKeysUtil.WEB_CONTEXT_AUTHORITY_URL);  

             if (StringUtils.isNotEmpty(authorityURL))  

             {  

                 authorityURLs = authorityURL.split(",");  

             }  

       

             // 判断当前的请求地址中是否存在需要过滤的后缀  

             if (authorityURL(req))  

             {  

                 // 不需要过滤的地址  

                 String allowAuthorityURL = config  

                         .getInitParameter(AKKeysUtil.WEB_CONTEXT_ALLOW_AUTHORITY_URL);  

                 if (StringUtils.isNotEmpty(allowAuthorityURL))  

                 {  

                     allowAuthorityURLs = allowAuthorityURL.split(",");  

                 }  

       

                 // 过滤不拦截的url  

                 if (allowAuthorityURL(req))  

                 {  

                     filterChain.doFilter(request, response);  

                     return;  

                 } else  

                 {  

                     // 判断当前用户是否登录,没有登录直接跳转到登录页面  

                     if (!relogin(redirectPath, response, req))  

                     {  

                         return;  

                     }  

                 }  

                   

                 // 最后对action与jsp进行权限校验  

                 // if (authorityRequestAddress(req))  

                 // {  

                 // 【暂时不实现纵向越权控制】  

                 filterChain.doFilter(request, response);  

                 // }  

                 // else  

                 // {  

                 // 没有权限时  

                 // noAuthority();  

                 // }  

             } else  

             {  

                 // 例如js,image,css等文件不列入权限控制范围内  

                 filterChain.doFilter(request, response);  

             }  

         }  

       

         @Override  

         public void init(FilterConfig filterConfig) throws ServletException  

         {  

             config = filterConfig;  

             // WebApplicationContext ctx = WebApplicationContextUtils  

             // .getWebApplicationContext(this.getServletContext());  

       

             // menuService = (MenuService) ctx.getBean("menuService");  

         }  

         /** 

          * 在未登陆的情况下允许访问的URL 

          *  

          * @return Boolean 

          */  

         private boolean allowAuthorityURL(HttpServletRequest request)  

         {  

             boolean isAllow = false;  

             // 获得当前访问的地址  

             String current_url = request.getRequestURI();  

       

             if (ArrayUtils.isNotEmpty(allowAuthorityURLs))  

             {  

                 for (String allowUrl : allowAuthorityURLs)  

                 {  

                     if (StringUtils.containsIgnoreCase(current_url, allowUrl))  

                     {  

                         isAllow = true;  

                         break;  

                     }  

                 }  

             }  

             return isAllow;  

         }  

       

         /** 

          * 需要过滤的后缀 

          *  

          * @return Boolean 

          */  

         private boolean authorityURL(HttpServletRequest request)  

         {  

             boolean isFilter = false;  

             if (ArrayUtils.isNotEmpty(authorityURLs))  

             {  

                 for (String suffix : authorityURLs)  

                 {  

                     if (request.getRequestURI().indexOf(suffix) != -1)  

                     {  

                         isFilter = true;  

                         break;  

                     }  

                 }  

             }  

             return isFilter;  

         }  

       

         /** 

          * 判断员工回话是否失效 

          *  

          * @param redirectPath 

          *            需要跳转的页面 

          * @param response 

          *            请求响应 

          *  

          * @param request 

          *            请求 

          *  

          * @throws IOException 

          *  

          * @return boolean 假:代表重新登录,真:代表session存在 

          */  

         private boolean relogin(String redirectPath, ServletResponse response,  

                 HttpServletRequest request) throws IOException  

         {  

             response.setContentType("text/html;charset=UTF-8");  

             response.setCharacterEncoding("UTF-8");  

             PrintWriter out = response.getWriter();  

             // 判断该用户是否存在session中,如果有直接进入当前action  

             if (null == request.getSession(true).getAttribute(  

                     AKKeysUtil.USER_EMPLOY_SESSION_KEY))  

             {  

                 // 跳转到登录界面  

                 out.print("<script language='javascript'>alert('身份验证失效,请重新登录!');window.parent.location.href='"  

                         + redirectPath + "';</script>");  

                 return false;  

             }  

       

             // 如果用户禁用掉cookie,则跳转到登录界面,提示用户启用cookie  

             Cookie[] cookies = request.getCookies();  

             if (null == cookies)  

             {  

                 // 1.可能用户清除过cookie 2.可能是由于用户禁用了cookie 此时都会跳转到登录界面  

                 // 跳转到登录界面  

                 out.print("<script language='javascript'>alert('Cookie被清理或是已禁用,请尝试重新登录!');window.parent.location.href='"  

                         + redirectPath + "';</script>");  

                 return false;  

             }  

             return true;  

         }  

     }  

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

    servlet过滤器并不等同于拦截器,常用的拦截器莫过于框架所自带的,如:Struts2spring mvc等。  如想达到权限认证(是否登陆、未登录返回登陆页面),通过框架的拦截器达到其效果,当然也可以直接使用servletfilter.

    非常感谢各位查看我的随笔。 这些随笔是在生活中遇到的一些问题和解决方案或者是相关的知识。 希望对大家会有一些帮助。 如果有帮到各位的地方,希望可以对作者进行一定的捐助,谢谢。 https://files.cnblogs.com/files/zz-blog/zhifubao.bmp
  • 相关阅读:
    Linux如何自动获取IP地址
    jq操作select集合
    UDP and TCP
    IPv6
    DHCP, NAT
    队列之顺序存储实现
    ARP, Fragmentation and Reassembly
    Classless Interdomain Routing (CIDR)
    Subnet Routing Examples
    Subnetting
  • 原文地址:https://www.cnblogs.com/zz-blog/p/8078925.html
Copyright © 2020-2023  润新知