一、简介
在Servlet2.3规范中定义了过滤器,它对servlet容器调用servlet的过程进行拦截,从而在servlet进行响应处理的前后实现一些特殊的功能。
过滤器实现了一个责任链的模式。多个过滤器形成一个过滤器链,过滤器链中不同过滤器的先后顺序由部署文件web.xml中过滤器映射<filter-mapping>的顺序决定。
最先截获客户端请求的过滤器将最后截获Servlet/JSP的响应信息。
Servlet过滤器可以过滤的Web组件包括Servlet,JSP和HTML等文件。
Servlet过滤器可以应用在客户端和servlet之间、servlet和servlet或JSP页面之间,以及所包括的每个JSP页面之间。
二、原理
在Servlet中使用过滤器时,过滤器可以对客户端的请求进行处理。处理完成后,它会交给下一个过滤器处理,这样,客户的请求在过滤链里逐个处理,直到请求发送到目标为止。在目标处理结束后,会沿着最后一个过滤器反向一个个进行处理直至返回到客户端。三、Filter相关接口
1. Filter接口
所有的Servlet过滤器都必须实现javax.servlet.Filter接口,并实现该接口中的三个方法:
init(FilterConfig filterConfig)
Servlet过滤器的初始化方法,Servlet容器创建Servlet过滤器实例后将调用该方法。该方法将读取web.xml文件中Servlet过滤器的初始化参数。
该方法在tomcat启动的时候执行。doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法。FilterChain用户访问后续过滤器。
这里的ServletRequest和ServletResponse一般需要转换成具体的Servlet实现对于的对象,如:HttpServletRequest和HttpServletResponse。
有些过滤器比较消耗资源,所以需要防止重复过滤,可以在doFilter()方法中判断。
destroy()
Servlet容器在销毁过滤器实例前调用该方法,在该方法中释放Servlet过滤器占用的资源。
2. FilterConfig接口
Filter的init方法中提供了一个FilterConfig对象,提供相关的操作:
如获取Filter中配置的初始化参数:<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>cn.heimar.LoginFilter</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</init-param>
</filter>
在init方法中获取:
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//获取Filter初始化参数
String username = filterConfig.getInitParameter("username");
}
3. 在Filter中访问application
ServletContext context = filterConfig.getServletContext();
或者在doFilter方法中根据转换好的request获取:
HttpServletRequest req = (HttpServletRequest)request;
ServletContext context = req.getSession().getServletContext();
四、定义过滤器
public class MyFilter implements Filter {
public void init(FilterConfig fc) {
//过滤器初始化代码
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain){
//在这里可以对客户端请求进行检查
//沿过滤器链将请求传递到下一个过滤器。
chain.doFilter(request, response);
//在这里可以对响应进行处理
}
public void destroy( ) {
//过滤器被销毁时执行的代码
}
}
五、过滤器映射
在web.xml文件中添加如下代码来声明Filter:<filter>
<filter-name>MyFilter</filter-name>
<filter-class>
cn.edu.uibe.webdev.MyFilter
</filter-class>
<init-param>
<param-name>developer</param-name>
<param-value>TongQiang</param-value>
</init-param>
</filter>
<!--针对一个Servlet做过滤-->
<filter-mapping>
<filter-name>MyFilter</filter-name>
<servlet-name>MyServlet</servlet-name>
</filter-mapping>
<!--针对URL Pattern做过滤-->
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/book/*</url-pattern>
</filter-mapping>
/* 拦截所有资源及不存在的资源
*.jsp 拦截所有jsp文件
默认情况下forward方式不会被过滤。一般是需要过滤的,方式是在filter-mapping中添加<dispatcher>FORWARD</dispatcher>,该值默认是request,添加时为了防止覆盖request,需要把该值也添加。六、常见应用
可以对客户提交的数据进行重新编码。使浏览器不缓存页面。
过滤不和谐的文字。
可以验证用户是否登录。
对客户端提交的数据进行重新编码示例:
EncodingFilter.java
package cn.heimar.filter.encoding;
import java.io.IOException;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EncodingFilter implements Filter {
/**
* 设置编码格式
*/
private String encoding;
/**
* 是否需要强制转码
*/
private boolean forceEncoding = false;
@Override
public void init(FilterConfig config) throws ServletException {
encoding = config.getInitParameter("ENCODING");
String force = config.getInitParameter("FORCE_ENCODING");
if (force != null)
forceEncoding = Boolean.valueOf(force);
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
if ((request.getCharacterEncoding() == null || forceEncoding)
&& encoding != null){
request.setCharacterEncoding(encoding);
}
response.setCharacterEncoding(encoding);
chain.doFilter(req, resp);
}
@Override
public void destroy() {
}
}
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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>cn.heimar.filter.encoding.EncodingFilter</filter-class>
<!-- 配置编码格式 -->
<init-param>
<param-name>ENCODING</param-name>
<param-value>utf-8</param-value>
</init-param>
<!-- 配置是否强转 -->
<init-param>
<param-name>FORCE_ENCODING</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>cn.heimar.filter.encoding.LoginServlet</servlet-class>
</servlet>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>