Filter
过滤器就是一个对所有的请求进行intercept(拦截),然后对请求进行相应的处理,或者servlet处理完成之后,对response进行处理等。
而这一切,servlet永远不可能知道。
Filter和Servlet的相同点
1 容器也知道Filter的API
一旦一个java类实现了Filter接口,他就正式的成为了一个过滤器,容器中它也就被注册了。
2 容器管理他们的生命周期
他们也有init和destory方法,不同的是servlet有service方法(doGet/doPost),而filter拥有的是doFileter()方法
3 他们都是被部署在DD中
一个程序可能会拥有多个filter,并且DD中配置了哪一个filter会执行,按照什么顺序执行等。
实现一个Filter
如下是一个基本的Filter。
public class BeerRequestFilter implements Filter { private FilterConfig fc; public void init(FilterConfig config) throws ServletException { this.fc = config; } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest httpReq = (HttpServletRequest) req; String name = httpReq.getRemoteUser(); if (name != null) { fc.getServletContext().log(“User “ + name + “ is updating”); } chain.doFilter(req, resp); } public void destroy() { // do cleanup stuff } }
1 init方法,接受一个FilterConfig对象作为参数,一般用来初始化Filter中的FilterConfig;
2 destory方法,基本上就是一个空方法;
3 doFilter(ServletRequest req, ServletResponse res, FilterChain chain),前两个参数就是传递进来的请求和响应,而chain是Filter的过滤链。
虽然是ServletRequest,但是我们可以保证他就是一个HttpServletRequest,同理,ServletResponse也肯定是一个HttpServletResponse。
chain.doFileter(req, res);是得以下一个Filter或者是Servlet能够继续进行的原因。
从FilterConfig中能够获得到一个ServletContext对象。
DD 设定
filter中filter-name和filter-class是必须的
<filter> <filter-name>BeerRequest</filter-name> <filter-class>com.example.web.BeerRequestFilter</filter-class> <init-param> <param-name>LogFileName</param-name> <param-value>UserLog.txt</param-value> </init-param> </filter>
filter-mapping中的filter-name是必须的,另外url-pattern或者servlet-name也是必须的
<filter-mapping> <filter-name>BeerRequest</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping>
或
<filter-mapping> <filter-name>BeerRequest</filter-name> <servlet-name>AdviceServlet</servlet-name> </filter-mapping>
对response进行处理
如果想要对response进行处理的话,只需要在
chain.doFilter(req, res);后面进行即可,因为在doFilter的时候已经能够保证servlet已经被执行完成了。
wrapper
1 Filter的chain.doFilter(req, res);调用之后,request和response对象传递给下一个filter或者servlet。
2 Servlet执行它的doPost或者doGet方法之后,会跳出方法调用栈,然后filter处在栈的顶层。
3 Servlet完成之后,response会直接发送给客户端,而不是先返回给filter。
4 所以在filter中的chain.doFilter之后的代码对response的处理都太晚了。
所谓的包装器就是把一个HttpServletRequest或者一个HttpServletResponse对象进行包装,其实质就是把默认的行为进行修改。
有四个Wrapper,分别为:
ServletRequestWrapper
ServletResponseWrapper
HttpServletRequestWrapper
HttpServletResponseWrapper
其中后两种用途较大,HttpServletRequestWrapper已经实现了HttpServletRequest接口了。同样HttpServletResponseWrapper实现了HttpServletResponse接口。
我们只需要把想要修改的行为进行@Override或者追加新的机能就可以了。
Head-First Servelts&JSP reading note 5