过滤器就是在源数据和目的数据之间起过滤作用的中间组件。对于Web应用程序来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和资源之间的请求与相应信息,并对这些信息进行过滤。
当Web容器接收到一个对资源的请求时,它将判断是否有过滤器与这个资源相关联。
如果有关联,那么容器将把请求交给过滤器进行处理。在过滤器中,可以改变请求的内容,或者重新设置请求的报头信息,然后再将请求发送给目标资源。当目标资源对请求作出响应时,容器同样会将响应先转发给过滤器,在过滤器中,可以对响应的内容进行转换,然后再将响应发送到客户端。
在一个Web应用程序中,可以部署多个过滤器,这些过滤器组成一个过滤器链。
在请求资源时,过滤器链中的过滤器将依次对请求进行处理,并将请求传递给下一个过滤器,知道目标资源;在发送响应时,则按照相反的顺序对响应进行处理,直到客户端。
过滤器并不是必须要将请求传送到下一个过滤器(或目标资源),它也可以自行对请求进行处理,然后发送响应给客户端,或者将请求转发给另一个目标资源。
一、Filter接口
开发过滤器要实现javax.servlet.Filter接口,并提供一个公开的不带参数的构造方法。
1、public void init(FilterConfig filterConfig)throws ServletException
Web容器调用该方法来初始化过滤器。利用filterConfig对象可以得到ServletContext对象,以及web.xml中配置的过滤器初始化参数。
2、public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)throws ServletException,IOException
当客户端请求目标资源的时候,容器就会调用与这个目标资源相关联的过滤器的doFilter()方法。在这个方法中,可以对请求和响应进行处理,实现过滤器的特定功能。
在特定的操作完成后,可以调用chain.doFilter(request,response)将请求传给下一个过滤器(或目标资源),也可以直接向客户端返回响应的信息,或者利用RequestDispatcher的forward()和include()方法,以及HttpServletResponse的sendRedirect()方法将请求转向到其他资源。
3、public void destroy()
Web容器调用该方法指示过滤器的生命周期结束。可以释放过滤器使用的资源。
Filter接口并没有相应的实现类可供继承,要开发过滤器,只能直接实现Filter接口。
FilterConfig接口用于在过滤器初始化时向其传递信息。它由容器实现,容器将其实例作为参数传入过滤器对象的init()方法中.
FilterChain接口由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中。过滤器对象使用FilterChain对象调用过滤器链中的下一个过滤器,如果该过滤器是链中最后一个过滤器,那么将调用目标资源。它只有一个方法:
public void doFilter(ServletRequest request,ServletResponse response)throws IOException,ServletException
过滤器的部署
需要在web.xml中对过滤器进行配置,这是通过<\filter>和<\filter-mapping>元素来完成的。
<filter>
<!--过滤器的名字,不能为空-->
<filter-name></filter-name>
<!--指定过滤器的完整的限定类名-->
<filter-class></filter-class>
<!--用于为过滤器指定初始化参数-->
<init-param>
<param-name></param-name>
<param-value></param-value>
</init-param>
</filter>
Servlet容器对部署描述符中声明的每一个过滤器,只创建一个实例。与Servlet类似,容器将在同一个过滤器实例上运行多个线程来同时为多个请求服务,因此要注意线程安全问题。如果对同一个过滤器声明两次,那么容器将会创建两个相同的过滤器类的实例。
<!--filter mapping指定过滤器关联的URL或者Servlet-->
<filter-mapping>
<!--name值可以是之前声明的过滤器的名字,也可以是*号,来匹配所有的Servlet-->
<filter-name></filter-name>
<!--用户在访问指定的URL或指定的servlet时,该过滤器才会被容器调用-->
<!--指定过滤器关联的URL样式,可出现多次-->
<url-pattern></url-pattern>
<!--指定过滤器对于的servlet,可出现多次-->
<servlet-name></servlet-name>
<servlet-name></servlet-name>
<url-pattern></url-pattern>
<!--指定过滤器的请求方式,可以有0-4个,默认是REQUEST。其值可以是INCLUDE/FORWARD/ERROR/REQUEST-->
<dispatcher></dispatcher>
<dispatcher></dispatcher>
</filter-mapping>
REQUEST:当用户之间访问页面时,Web容器将会调用过滤器。如果目标资源是通过ResquestDispatcher的include()或forward()方法访问的,那么该过滤器将不会被调用。
INCLUDE:如果目标资源是通过ResquestDispatcher的include()方法访问时,该过滤器将被调用。除此之外,过滤器不会被调用。
FORWARD:如果目标资源是通过ResquestDispatcher的forward()方法访问的,那么该过滤器将被调用,除此之外,过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用的,那么该过滤器将被调用,除此之外,过滤器不会被调用。
1、自定义一个过滤器:
public class SimpleFilter implements Filter {
public void init(FilterConfig filterConfig)throws ServletException{
ServletContext servletContext=filterConfig.getServletContext();
String name=filterConfig.getInitParameter("name");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws ServletException,IOException{
response.setContentType("text/html;charset=GB2312");
PrintWriter out=response.getWriter();
out.println("before doFilter()");
chain.doFilter(request,response);
out.println("after doFilter()");
out.close();
}
public void destroy(){
}
}
2、在web.xml中进行配置:
<filter>
<filter-name>SimpleFilter</filter-name>
<filter-class>org.wdz.filter.SimpleFilter</filter-class>
<init-param>
<param-name>name</param-name>
<param-value>test</param-value>
</init-param>
</filter>
<!--filter mapping指定过滤器关联的URL或者Servlet-->
<filter-mapping>
<filter-name>SimpleFilter</filter-name>
<!--当访问test.jsp就会先调用该过滤器-->
<url-pattern>/test.jsp</url-pattern>
</filter-mapping>
对请求和响应数据进行替换的过滤器
HttpServletRequest类并没有提供对请求信息进行修改的setXXX()方法。而HttpServletResponse类也没有提供得到响应数据的方法。也就是说,虽然过滤器可以截取到请求和响应的对象,但是却无法直接使用这两个对象对它们的数据进行替换。
我们可以利用请求和响应的包装类来间接改变请求和响应的信息。
在Servlet规范中,共有4种包装类:
public class ServletRequestWrapper implements ServletRequest
public class ServletResponseWrapper implements ServletResponse
public class HttpServletRequestWrapper implements HttpServletRequest
public class HttpServletResponseWrapper implements HttpServletResponse
它们在构造方法中接受真正的请求或响应对象,然后利用该对象来完成自己需要实现的方法。
1、自定义一个包装类,覆盖想要修改的方法:
public class MyRequestWrapper extends HttpServletRequestWrapper {
public MyRequestWrapper(HttpServletRequest request){
//它们的构造方法接受真正的请求对象
super(request);
}
//覆盖父类中的方法,满足自己的需要
@Override
public String getParameter(String name) {
//通过父类来获取请求参数的值
String value=super.getParameter(name);
//可以对value进行处理,然后返回
return value;
}
}
2、在过滤器中:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//先进行转换
HttpServletRequest httpReq=(HttpServletRequest)servletRequest;
//替换为自定义的MyRequestWrapper
filterChain.doFilter(new MyRequestWrapper(httpReq),servletResponse);
}
之后,在目标资源的代码中,可以调用request.getParamter()方法就会得到处理后的值。