原文链接https://dotblogs.com.tw/alantsai/2013/10/10/servlet-filter
1.Filter基本结构
Filter就像是 Client 以及 Servlet之间的看门人,无论进出都要经过他。
Filter功能很强大,可以实现很多功能。比如:
记录有谁进出(log往来的request)、限制谁可以进入(未登录不能进入)、检查违禁物品(例如过滤掉sql injection)、出门时打上标签(例如给返回的图片做水印)
Filter可以有很多个,所以又称为Filter Chain,每一个Filter关注一个事情就ok
2.Filter的作用
在web开发中经常会有,跳转不同页面前判断用户是否登录的逻辑,当然这些都可以在Servlet中实现,但是如果有20个Servlet都需要加入这段逻辑,就显得有些冗余了。此时需要引出Servlet的看门人Filte。
Filter 翻译为过滤器 前面举得那个是否登录的例子就是一个“过滤”体现 除了单纯过滤(分发)之外,Filter还可以对request response内容进行修改
eg: 将所有进来的request response都是用UTF-8 编码 ,此时可以使用Filter来实现
1 <filter> 2 <filter-name>encodingFilter</filter-name> 3 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 4 <init-param> 5 <param-name>encoding</param-name> 6 <param-value>UTF-8</param-value> 7 </init-param> 8 <init-param> 9 <param-name>forceEncoding</param-name> 10 <param-value>true</param-value> 11 </init-param> 12 </filter> 13 <filter-mapping> 14 <filter-name>encodingFilter</filter-name> 15 <url-pattern>/*</url-pattern> 16 </filter-mapping>
3.Filter具体实现
javax.Servlet.Filter这个interface 有三个方法需要实现
1.public void init(FilterConfig config)
2.public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
3.public void destroy()
其中init destroy 方法都只会执行一次 目的是初始化和释放资源 而实际工作都在doFilter里面
doFilter比较特别的地方是FilterChain FilterChain记录的是下一个关卡是谁
PS:这些Filter对象都保存在ApplicationFilterChain对象的数组中,在FilterChain链上每执行一个Filter对象,数组当前计数都会+1,直到计数等于数组长度。当FilterChain上所有的Filter对象执行完成后,就会执行最终的 Servlet
1 public void doFilter(ServletRequest request, ServletResponse, FilterChain chain) 2 ,throws ServletException, IOException 3 { 4 //這邊是在request進來做處理的地方 5 doFilter(request, response); 6 //这边我理解是response出来做处理的地方,这条链子的终点到 7 //Servlet,在回到这边未执行完的方法中,对response进行加工处理 8 }
有了看门人之后,需要通知程序在哪些“位置”(url-pattern),针对哪些“请求”(dispatcher),需要设置看门人。
1 <filter> 2 <filter-name>logFilter</filter-name> 3 <filter-class>filter.LogFilter</filter-class> 4 <init-param> 5 <param-name>firstParam</param-name> 6 <param-value>this is first init value</param-value> 7 </init-param> 8 </filter> 9 10 <filter-mapping> 11 <filter-name>logFilter</filter-name> 12 <url-pattern>*</url-pattern> 13 <dispatcher>REQUEST</dispatcher> 14 </filter-mapping>
值得注意的是<dispatcher> 这个标签的内容表示在什么情况下Servlet需要执行这个Filter,默认是Request
REQUEST
:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。INCLUDE
:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。FORWARD
:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。ERROR
:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
4.责任链模式在TomCat中的应用
其实在真正执行到TestFilter类之前,会经过很多Tomcat内部的类。顺带提一下其实Tomcat的容器设置也是责任链模式,注意被红色方框所圈中的类,从Engine到Host再到Context一直到Wrapper都是通过一个链传递请求。被绿色方框所圈中的地方有一个名为ApplicationFilterChain的类,ApplicationFilterChain类所扮演的就是抽象处理者角色,而具体处理者角色由各个Filter扮演。