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渲染了对应的视图之后执行
- 这个方法的主要作用是用于进行资源清理工作的
二者区别#
Filter | Interceptor | Summary |
---|---|---|
Filter 接口定义在 javax.servlet 包中 | 接口 HandlerInterceptor 定义在org.springframework.web.servlet 包中 | |
Filter 定义在 web.xml 中 | ||
Filter在只在 Servlet 前后起作用。Filters 通常将 请求和响应(request/response) 当做黑盒子,Filter 通常不考虑servlet 的实现。 | 拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户介入(hook into)请求的生命周期,在请求过程中获取信息,Interceptor 通常和请求更加耦合。 | 在Spring构架的程序中,要优先使用拦截器。几乎所有 Filter 能够做的事情, interceptor 都能够轻松的实现 |
Filter 是 Servlet 规范规定的。 | 而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。 | 使用范围不同 |
Filter 是在 Servlet 规范中定义的,是 Servlet 容器支持的。 | 而拦截器是在 Spring容器内的,是Spring框架支持的。 | 规范不同 |
Filter 不能够使用 Spring 容器资源 | 拦截器是一个Spring的组件,归Spring管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如 Service对象、数据源、事务管理等,通过IoC注入到拦截器即可 | Spring 中使用 interceptor 更容易 |
Filter 是被 Server(like Tomcat) 调用 | Interceptor 是被 Spring 调用 | 因此 Filter 总是优先于 Interceptor 执行 |
拦截器(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";
}
}