Filter
Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是
- 设置字符集
- 控制权限
- 控制转向
- 业务逻辑判断
工作流程
在web.xml文件配置好要拦截的客户端请求,拦截请求
对请求或响应(Request、Response)统一设置编码,简化操作
进行逻辑判断,如用户是否已经登陆、有没有权限访问该页面等等工作
将请求交给Servlet进行处理并生成响应
最后Filter再对服务器响应进行后处理
生命周期
它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。
Filter可以认为是Servlet的一种“加强版”,是个典型的处理链
- 对用户请求进行预处理
- 也可以对HttpServletResponse进行后处理
- Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应
Filter种类
- 用户授权Filter: 负责检查用户请求,根据请求过滤用户非法请求
- 日志Filter: 详细记录某些特殊的用户请求
- 解码的Filter: 包括对非标准编码的请求解码
- 改变XMLFileter: XSLT Filter
Filter可以负责拦截多个请求或响应,一个请求或响应也可以被多个Filter拦截
创建Filter
- 创建Filter处理类
- web.xml文件中配置Filter
创建Filter必须实现javax.servlet.Filter接口,在该接口中定义了如下三个方法。
// 用于完成Filter的初始化。 void init(FilterConfig config) // 用于Filter销毁前,完成某些资源的回收。 void destory() // 实现过滤功能,该方法就是对每个请求及响应增加的额外处理 // 该方法可以实现对用户请求进行预处理(ServletRequest request) // 也可实现对服务器响应进行后处理(ServletResponse response) // 它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;
// 执行该方法之后,即对服务器响应进行后处理。 void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
Interceptor
拦截器是在AOP中应用
在service或者一个方法前调用一个方法,或者在方法后调用一个方法。
基于JAVA的反射机制
拦截器
在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作。
拦截是AOP的一种实现策略。
在WebWork的中文文档的解释为—拦截器是动态拦截Action调用的对象
- 提供了一种机制使开发者可以定义在一个Action执行的前后执行的代码,也可以在一个Action执行前阻止其执行。
- 同时也提供了一种可以提取Action中可重用的部分的方式。
- 拦截器将Action共用的行为独立出来,在Action执行前后执行。
- 这也就是我们所说的AOP,它是分散关注的编程方法,它将通用需求功能从不相关类之中分离出来;
- 能够共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
拦截器将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为就有很好的重用性
Interceptor在SpringMVC中的工作流程
当你提交对Action(默认是.action结尾的url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action
在Action执行之前,调用被Interceptor截取,Interceptor在Action执行前后执行
SpringMVC中的Interceptor 拦截请求是通过HandlerInterceptor来实现的
在SpringMVC 中定义一个Interceptor 非常简单
- 定义的Interceptor类实现了Spring 的HandlerInterceptor 接口,或者这个类继承实现了HandlerInterceptor 接口的类
- 定义的Interceptor类实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类
preHandle (HttpServletRequest request, HttpServletResponse response, Object handle)
该方法将在请求处理之前进行调用,SpringMVC 中的Interceptor是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor
- 每个Interceptor的调用会依据它的声明顺序依次执行
- 最先执行的都是Interceptor中的preHandle方法
- 可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理
- 也可以在这个方法中进行一些判断来决定请求是否要继续进行下去
- 该方法的返回值是布尔值Boolean类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行
- 当返回值为true 时就会继续调用下一个Interceptor的preHandle 方法
- 如果已经是最后一个Interceptor的时候就会是调用当前请求的Controller 方法
postHandle方法都只能是在当前所属的Interceptor的preHandle方法的返回值为true时才能被调用
postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)
postHandle方法,顾名思义就是在当前请求进行处理之后,也就是Controller方法调用之后执行
- 会在DispatcherServlet进行视图返回渲染之前被调用
- 可以在这个方法中对Controller处理之后的ModelAndView对象进行操作
postHandle 方法被调用的方向跟preHandle是相反的,也就是说先声明的Interceptor的postHandle方法反而会后执行
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)
该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。
- 该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行
- 这个方法的主要作用是用于进行资源清理工作的
二者区别
拦截器(Interceptor)和过滤器(Filter)的执行顺序
过滤前-拦截前-Action处理-拦截后-过滤后
Filter的demo
xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <filter> <filter-name>filterDemo</filter-name> <filter-class>cn.techny.filterDemo.filterDemo</filter-class> <init-param> <!-- 为filter1的私有属性配置值--> <param-name>paraName</param-name> <param-value>paraValue</param-value> </init-param> </filter> <filter-mapping> <filter-name>filterDemo</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>ServletDemo</servlet-name>
<servlet-class>cn.techny.ServletDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
filterDemo
package cn.techny.filterDemo; 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; public class filterDemo implements Filter{ private String paraName; public void init(FilterConfig config) throws ServletException{ paraName = config.getInitParameter("paraName"); System.out.println("init filterDemo, paraName=" + paraName); } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException{ System.out.println("Before filterDemo, paraName=" + paraName); chain.doFilter(req, resp); System.out.println("After filterDemo, paraName=" + paraName); } public void destroy(){ System.out.println("Destory filterDemo"); paraName = null; } }
servletDemo
package cn.techny.filterDemo; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo extends HttpServlet{ /** * */ private static final long serialVersionUID = 4657145885789315799L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("do get..."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("dopost..."); } }
注解配置
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.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; @WebFilter(urlPatterns={"/dev/*", "/login/*"}, displayName="WebFilterDemo", description="WebFilter Demo", filterName="WebFilterDemo") @Component public class WebFilterLogin implements Filter{ public void init(FilterConfig filterConfig) { System.out.println("WebFilterLogin init()"); System.out.println(filterConfig.getFilterName()); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; String url = request.getRequestURL().toString(); System.out.println("Enter WebFilterDemo " + url); chain.doFilter(req, res); } }
Interceptor的Demo
Interceptor配置
@Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { /* * 拦截器配置 */ @Override public void addInterceptors(InterceptorRegistry registry) { // 注册自定义拦截器,添加拦截路径和排除拦截路径 registry.addInterceptor(new Test1Interceptor()) // 添加拦截器 .addPathPatterns("/**") // 拦截路径 .excludePathPatterns( // 不拦截路径 "/hello").order(0);//执行顺序 super.addInterceptors(registry); } }
InterceptorDemo
public class InterceptorDemo implements HandlerInterceptor{ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception { System.out.println("执行preHandle方法"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("执行postHandle方法"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("执行afterCompletion方法"); } }
测试Interceptor
@RestController public class TestController { @RequestMapping("/hello") public String getHello() { System.out.println("这里是Hello"); return "hello world"; } @RequestMapping("/test1") public String getTest1() { System.out.println("这里是Test1"); return "test1 content"; } @RequestMapping("/test2") public String getTest2() { System.out.println("这里是Test2"); return "test2 content"; } }