Java中Servlet Filter拦截器详解
Filter的定义是在请求一个资源或者从一个资源返回信息的时候执行过滤操作的插件。Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,一般常用于实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
定义
//该方法在客户端请求及服务器端回复时都将被自动调用 public void doFilter (ServletRequest, ServletResponse, FilterChain) //初始化配置参数,在doFilter()方法之前被调用 public void init(FilterConfig filterConfig) //结束过滤器,doFilter()方法完成后被调用 public void destroy()
doFilter参数:
ServletRequest:对于简单的过滤器,大多数过滤逻辑是基于这个对象的。如果处理HTTP请求,并且需要访问诸如getHeader或getCookies等在ServletRequest中无法得到的方法,就要把此对象构造成 HttpServletRequest。
ServletResponse:除了在两个情形下要使用它以外,通常忽略这个参数。首先,如果希望完全阻塞对相关 servlet或JSP页面的访问。可调用response.getWriter并直接发送一个响应到客户机。其次,如果希望修改相关的servlet或 JSP页面的输出,可把响应包含在一个收集所有发送到它的输出的对象中。然后,在调用serlvet或JSP页面后,过滤器可检查输出,如果合适就修改 它,之后发送到客户机。
FilterChain:对此对象调用doFilter以激活与servlet或JSP页面相关的下一个过滤器。如果没有另一个相关的过滤器,则对doFilter的调用激活servlet或JSP本身。
1. init方法只在此过滤器第一次初始化时执行,不是每次调用过滤器都执行它。对于简单的过滤器,可提供此方法的一个空体,但有两个原因 需要使用init。首先,FilterConfig对象提供对servlet环境及web.xml文件中指派的过滤器名的访问。因此,普遍的办法是利用 init将 FilterConfig对象存放在一个字段中,以便doFilter方法能够访问servlet环境或过滤器名.其次,FilterConfig对象具 有一个getInitParameter方法,它能够访问部署描述符文件(web.xml)中分配的过滤器初始化参数。
2. Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源(拦截url)进行拦截后,WEB服务器每次在调用web资源之前,都会先调用一下filter的doFilter方法。
3. web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
4. 可利用destroy来完成诸如关闭过滤器使用的文件或数据库连接池等清除任务。
Filter原理
创建Filter
1. 建立一个实现Filter接口的类
所有过滤器都必须实现javax.servlet.Filter。这个接口包含三个方法,分别为doFilter、init和destroy。
2. 将过滤行为放入doFilter方法
doFilter方法为大多数过滤器地关键部分。每当调用一个过滤器时,都要执行doFilter。对于大多数过滤器来说,doFilter执行的步骤是 基于传入的信息的。因此,可能要利用作为doFilter的第一个参数提供的ServletRequest。这个对象常常构造为 HttpServletRequest类型,以提供对该类的更特殊方法的访问。
3. 调用FilterChain对象的doFilter方法
Filter接口的doFilter方法以一个FilterChain对象作为它的第三个参数。在调用该对象的doFilter方法时,激活下一个相关的 过滤器。这个过程一般持续到链中最后一个过滤器为止。在最后一个过滤器调用其FilterChain对象的doFilter方法时,激活servlet或页面自身。但是,链中的任意过滤器都可以通过不调用其FilterChain的doFilter方法中断这个过程。在这样的情况下,不再调用JSP页面的serlvet,并且中断此调用过程的过滤器负责将输出提供给客户机。
4. 对适当的servlet和JSP页面注册过滤器
web.xml中有两个用于过滤器的元素,分别是:filter和filter-mapping。filter元素向系统注册一个过滤对象,filter-mapping元素指定该过滤对象所应用的URL。
<web-app> <filter> <filter-name>MyFilter</filter-name> <filter-class>myPackage.FilterClass</filter-class> </filter> <filter-mapping> <filter-name>MyFilter</filter-name> <url-pattern>/someDirectory/SomePage.jsp</url-pattern> </filter-mapping> </web-app>
5. 禁用激活器servlet。防止用户利用缺省servlet URL绕过过滤器设置
在对资源应用过滤器时,可通过指定要应用过滤器的URL模式或servlet名来完成。如果提供servlet名,则此名称必须与 web.xml的servlet元素中给出的名称相匹配。如果使用应用到一个serlvet的URL模式,则此模式必须与利用web.xml的元素 servlet-mapping指定的模式相匹配。但是,多数服务器使用“激活器servlet”为servlet体统一个缺省的URL:http://host/WebAppPrefix/servlet/ServletName。 需要保证用户不利用这个URL访问servlet(这样会绕过过滤器 设置)。
Filter应用场景
1、统一POST请求中文字符编码的过滤器
2、控制浏览器缓存页面中的静态资源的过滤器
有些动态页面中引用了一些图片或css文件以修饰页面效果,这些图片和css文件经常是不变化的,所以为减轻服务器的压力,可以使用filter控制浏览器缓存这些文件,以提升服务器的性能。
3、使用Filter实现URL级别的权限认证
在实际开发中我们经常把一些执行敏感操作的servlet映射到一些特殊目录中,并用filter把这些特殊目录保护起来,限制只能拥有相应访问权限的用户才能访问这些目录下的资源。从而在我们系统中实现一种URL级别的权限功能。
4、实现用户自动登陆
首先,在用户登陆成功后,发送一个名称为user的cookie给客户端,cookie的值为用户名和md5加密后的密码。编写一个AutoLoginFilter,这个filter检查用户是否带有名称为user的cookie,如果有,则调用dao查询cookie的用户名和密码是否和数据库匹配,匹配则向session中存入user对象(即用户登陆标记),以实现程序完成自动登陆。
例子
//web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>FilterTest</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <filter> <display-name>EcodingFilter</display-name> <filter-name>EcodingFilter</filter-name> <filter-class>org.nb.filter.EnCodeFilter</filter-class> <init-param> <param-name>EncodeCoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>EcodingFilter</filter-name> <servlet-name>hello</servlet-name> <url-pattern>*</url-pattern> </filter-mapping> <servlet> <servlet-name>hello</servlet-name> <servlet-class></servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
//HelloServlet.java @WebServlet("/helloServlet") public class HelloServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); out.println("<font color=red>Hello.</font>"); } }
//EnCodeFilter.xm public class EnCodeFilter implements Filter { Map<String, String> params = new HashMap<String, String>(); @Override public void destroy() { System.out.println("EncodeFilter destroy"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String encodeCoding = params.get("EncodeCoding"); request.setCharacterEncoding(encodeCoding); response.setCharacterEncoding(encodeCoding); chain.doFilter(request, response); System.out.println("EncodeFilter doFilter"); } @Override public void init(FilterConfig cfg) throws ServletException { Enumeration<String> names = cfg.getInitParameterNames(); while (names.hasMoreElements()) { String name = names.nextElement(); params.put(name, cfg.getInitParameter(name)); } System.out.println("EncodeFilter init"); } }
在tomcat启动的时候Console输出的内容:
EncodeFilter init
执行页面http://localhost:8080/FilterTest/helloServlet输出:
此时Console输出内容:
EncodeFilter doFilter
关闭tomcat的时候,Console输出的内容:
EncodeFilter destroy
总结
1. Filters是在web.xml中配置的插件,Servlets和Filters相互没有依赖,如果通过编辑web.xml来添加和删除过滤器。实现过滤器非常简单,只需要实现javax.servlet.Filter接口,就可以实现一个过滤器。
2. Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源(拦截url)进行拦截后,WEB服务器每次在调用web资源之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可以在调用目标资源之前,让一段代码执行。
3. web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。利用它可以在调用目标资源之后,让一段代码执行。
版权声明:本文为JAVASCHOOL原创文章,未经本站允许不得转载。