JavaWeb有三大组件,Servlet、Listener、Filter。本文将介绍Filter,主要从用处、种类、使用方法等进行介绍。
一、用处
Filter可以认为是Servlet的一种“加强版”。使用Filter完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
Filter有以下几个用处:
- 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest;
- 根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据;
- 在HttpServletResponse到达客户端之前,拦截HttpServletResponse;
- 根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。
二、种类
- 用户授权的Filter:Filter负责检查用户请求,根据请求过滤用户非法请求(比如对用户登录状态进行判定);
- 日志Filter:详细记录某些特殊的用户请求;
- 负责解码的Filter:包括对非标准编码的请求解码;
- 能改变XML内容的XSLT Filter等;
- Filter可负责拦截多个请求或响应;一个请求或响应也可被多个Filter拦截。
三、使用方法
3.1 创建Filter步骤
1)创建Filter处理类;
2)web.xml文件中配置Filter,或通过注解的方式配置。(顺便说一下,三大组件都需要在web.xml中进行配置)
3.2 创建Filter类
创建Filter类必须实现Filter接口,Filter接口中包含三个方法:
- void init(FilterConfig config):用于完成Filter的初始化;
- void destroy():用于Filter销毁前,完成某些资源的回收;
- void doFilter(ServletRequest srq, ServletResponse srp, FilterChain chain):实现过滤功能,该方法就是对每个请求及响应增加的额外处理。
doFilter()方法,在该方法中可实现对用户请求进行预处理,也可实现对服务器响应进行后处理,分界线就是是否调用了chain.doFiler(),调用之前是请求预处理,调用之后是响应后处理。这是因为,web服务器会检查FilterChain对象中是否还有Filter,如果有,则调用下一个Filter,没有,则调用目标资源。
3.3 配置Filter
与配置Servlet相似,配置Filter,需要配置两个部分:
1)配置Filter名;
2)配置Filter拦截URL模式
与Servlet的区别在于:Servlet通常只配置一个URL,而Filter可以同时拦截多个请求的URL。因此,在配置Filter的URL模式时通常会使用模式字符串,使得Filter可以拦截多个请求。配置的方式有两种:在Filter类中通过注解进行配置,在web.xml文件中进行配置。
3.3.1 注解配置
使用@WebFilter注解进行配置,并添加属性。常用属性如下:
属性 | 是否必需 | 说明 |
---|---|---|
asynSupported | 否 | 指定该Filter是否支持异步操作模式。 |
dispatcherTypes | 否 | 指定该Filter仅对那种dispatcher模式的请求进行过滤。该属性支持ASTNC、ERROR、FORWARD、INCLUDE、REQUEST这五个值的任意组合。默认值是同时过滤5种模式的请求。 |
displayName | 否 | 指定该Filter的显示名 |
filterName | 是 | 指定该Filter的名称 |
initParams | 否 | 用于为该Filter配置参数 |
servletNames | 否 | 该属性值可指定多个Servlet的名称,用于指定该Filter仅对这几个Servlet执行过滤。 |
urlPatterns/value | 否 | 这两个属性的作用完全相同。都指定该Filter所拦截的URL。 |
3.3.2 web.xml中进行配置
<!-- 定义Filter -->
<filter>
<filter-name>log</filter-name>
<filter-class>filter.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>log</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽出的通用代码。通过使用Filter可以实现更好的代码复用。
Filter和Servlet具有完全相同的生命周期行为,且Filter也可以通过<init-param.../>元素或@WebFilter的initParams属性来配置初始化参数,获取Filter的初始化参数则使用FilterConfig的getInitParameter()方法。
四、举个栗子
/**
* AuthorityFilter.java
*/
@WebFilter(filterName = "authority", urlPatterns = {"/*"}, initParams = {
@WebInitParam(name = "encoding",value = "UTF-8"),
@WebInitParam(name = "loginPage",value = "/login.jsp"),
@WebInitParam(name = "proLogin",value = "proLogin.jsp")
})
public class AuthorityFilter implements Filter{
private FilterConfig config;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
/**
* 通过config获取初始化参数
*/
String encoding = this.config.getInitParameter("encoding");
String loginPage = this.config.getInitParameter("loginPage");
String proLogin = this.config.getInitParameter("proLogin");
/**
* 通过获取到的初始化参数设置解码格式
*/
servletRequest.setCharacterEncoding(encoding);
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession(true);
String requestPath = httpServletRequest.getServletPath();
/**
* 若用户未登录,并且请求地址不是登录页和处理登录页,跳转到登录页;
* 若登录了,则调用filterChain.doFilter()返回资源。
*/
if (session.getAttribute("user")==null
&& !requestPath.endsWith(loginPage)
&& !requestPath.endsWith(proLogin))
{
httpServletRequest.setAttribute("tip","您还没有登录");
httpServletRequest.getRequestDispatcher(loginPage).forward(httpServletRequest,servletResponse);
} else {
filterChain.doFilter(httpServletRequest,servletResponse);
}
}
@Override
public void destroy() {
this.config = null;
}
}