Filter 介绍:
它主要用于对用户请求进行预处理,也可以对HttpServletResponse 进行后处理。使用Filter 的完整流程:Filter 对用户请求进行预处理,接着将请求交给Servlet 进行处理并生成响应,最后Filter 再对服务器响应进行后处理。
Filter 用处:
> 在 HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest 。
> 根据需要检查 HttpServletRequest ,也可以修改HttpServletRequest 头和数据。
> 在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。
> 根据需要检查 HttpServletResponse ,也可以修改HttpServletResponse头和数据。
Filter 种类:
> 用户授权的 Filter
> 日志 Filter
> 负责解码的 Filter
> Filter 可负责拦截多个请求或响应
创建一个Filter:
1、创建Filter类
必须实现javax.servlet.Filter接口,在该接口中定义了如下方法:
1、void init(FilerConfig config):用于完成Filter的初始化。
2、void destroy():用于Filter撤销前,完成某些资源的回收。
3、void doFilter(ServletRequest request,ServletResponse response, FilterChain chain):实现过滤功能,该方法就是对每一个请求及功能增加的额外处理。
package jbelial.Filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; public class LogFilter implements Filter { //FilterConfig用于访问Filter的配置信息 private FilterConfig config ; // 实现销毁 public void destroy() { // TODO Auto-generated method stub this.config = null ; } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub //-----------------对用户请求执行预处理----------------------- ServletContext context = this.config.getServletContext() ; long before = System.currentTimeMillis() ; System.out.println("开始过滤。。。。"); //将请求转换成HttpServletRequest 请求。 HttpServletRequest hrequest = (HttpServletRequest)request ; System.out.println("Filter 已经截获到用户的请求的地址:" + hrequest.getServletPath()); // Filter 只是链式处理,请求依然放行到目的地址 chain.doFilter(request, response) ; //---------------对服务器响应执行后处理----------------------- long after = System.currentTimeMillis() ; System.out.println("过滤结束。。。。"); System.out.println("请求被定位到"+hrequest.getRequestURI()+ " 所花时间:"+(after - before)); } // 实现初始化 public void init(FilterConfig config) throws ServletException { // TODO Auto-generated method stub this.config = config ; } }
实现该方法就可以实现对用户的请求进行预处理,也可以对服务器响应进行后处理——分界线为是否调用了chain.doFilter(request.response) 。
上面的请求Filter 仅在日志中记录请求的URL,对所有的请求都执行 chain.doFilter(request,response) 方法,当Filter 对请求过滤后依然将请求发送到目的地址。如果需要检查权限,可以在Filter中根据用户请求 HttpSession,判断用户权限是否足够。如果权限不够,直接调用重定向即可。
2、配置Filter
> 配置 Filter 名。
> 配置 Filter 拦截 URL 模式。
1、通过Annotation 进行配置
在Filter 类 中添加:
@WebFilter(filterName= "log",urlPatterns = {"/*"})
下面附上@WebFilter 支持的常用属性表
属性 | 是否必须 | 说明 |
asyncSupported | F | 指定该Filter是否支持异步操作模式。 |
dispatcherTypes | F |
指定该Filter仅对dispatchar模式的请求进行过滤。该属性支持ASYNC、ERROR、FORWARD、 INCLUDE、REQUST这5个值的任意组合。默认为同时过滤5种模式的请求。 |
displayName | F | 指定该Filter的显示名 |
filterName | 指定该Filter的名字 | |
initParams | F | 用于为该Filter配置参数 |
servletNames | F | 该属性值可指定多个Servlet的名称,用于指定该Filter仅对这几个Servlet执行过滤 |
urlPatterns | F | 指定该Filter所拦截的URL |
2、在web.xml 文件中配置:
<filter> <filter-name>log</filter-name> <filter-class>jbelial.Filter.LogFilter</filter-class> </filter> <filter-mapping> <filter-name>log</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Filter 的 doFilter()方法里面多了一个FilterChain 的参数,通过该参数可以控制是否放行用户请求。在实际项目中, Filter 里 doFilter() 方法里的代码就是从多个Servlet 的service() 方法里面抽取的通用代码,通过使用Filter 可以实现更好的代码复用。
如下面的代码:
@WebFilter(filterName="authority" , urlPatterns={"/*"} , initParams={ @WebInitParam(name="encoding", value="GBK"), @WebInitParam(name="loginPage", value="/login.jsp"), @WebInitParam(name="proLogin", value="/proLogin.jsp")}) public class AuthorityFilter implements Filter { //FilterConfig可用于访问Filter的配置信息 private FilterConfig config; //实现初始化方法 public void init(FilterConfig config) { this.config = config; } //实现销毁方法 public void destroy() { this.config = null; } //执行过滤的核心方法 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException { //获取该Filter的配置参数 String encoding = config.getInitParameter("encoding"); String loginPage = config.getInitParameter("loginPage"); String proLogin = config.getInitParameter("proLogin"); //设置request编码用的字符集 request.setCharacterEncoding(encoding); HttpServletRequest requ = (HttpServletRequest)request; HttpSession session = requ.getSession(true); //获取客户请求的页面 String requestPath = requ.getServletPath(); //如果session范围的user为null,即表明没有登录 //且用户请求的既不是登录页面,也不是处理登录的页面 if( session.getAttribute("user") == null && !requestPath.endsWith(loginPage) && !requestPath.endsWith(proLogin)) { //forward到登录页面 request.setAttribute("tip" , "您还没有登录"); request.getRequestDispatcher(loginPage) .forward(request, response); } //"放行"请求 else { chain.doFilter(request, response); } } }
如果用户没有登录,那么只能访问/login.jsp和/proLogin.jsp页面。
在 web.xml文件中配置该Filter:
<filter> <filter-name>authority</filter-name> <filter-class>jbelial.Filter.Authority</filter-class> <init-param> <param-name>encoding</param-name> <param-value>GBK</param-value> </init-param> <init-param> <param-name>loginPage</param-name> <param-value>/login.jsp</param-value> </init-param> <init-param> <param-name>proLogin</param-name> <param-value>/proLogin.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>authority</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>