拦截器介绍
Java中的拦截器是动态拦截 action 调用的对象,然后提供了可以在 action 执行前后增加一些操作,也可以在 action执行前停止操作,功能与过滤器类似,但是标准和实现方式不同。
- 登录认证:在一些应用中,可能会通过拦截器来验证用户的登录状态,如果没有登录或者登录失败,就会给用户一个友好的提示或者返回登录页面,当然大型项目中都不采用这种方式,都是调单点登录系统接口来验证用户。
- 记录系统日志:我们在常见应用中,通常要记录用户的请求信息,比如请求 ip,方法执行时间等,通过这些记录可以监控系统的状况,以便于对系统进行信息监控、信息统计、计算 PV、性能调优等。
- 通用处理:在应用程序中可能存在所有方法都要返回的信息,这是可以利用拦截器来实现,省去每个方法冗余重复的代码实现。
使用拦截器
我们需要实现 HandlerInterceptor 类,并且重写三个方法
- preHandle:在 Controoler 处理请求之前被调用,返回值是 boolean类型,如果是true就进行下一步操作;若返回false,则证明不符合拦截条件,在失败的时候不会包含任何响应,此时需要调用对应的response返回对应响应。
- postHandler:在 Controoler 处理请求执行完成后、生成视图前执行,可以通过ModelAndView对视图进行处理,当然ModelAndView也可以设置为 null。
- afterCompletion:在 DispatcherServlet 完全处理请求后被调用,通常用于记录消耗时间,也可以对一些资源进行处理。
1. 定义login的拦截器
public class LoginInterceptor implements HandlerInterceptor {
/**
* 进入controller方法之前
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("LoginInterceptor ==》进入preHandle");
//进入controller之前验证token的值
String token = request.getParameter("token");
System.out.println(request.getRequestURL());
//验证用户登录
Object user = request.getSession().getAttribute("user");
if (user != null) {
return true;
} else {
System.out.println("用户未登录...");
// request.getRequestDispatcher("/index.html").forward(request, response);
// response.sendRedirect(request.getContextPath()+"login.html");
response.sendRedirect("/login.html");
return false;
}
/* response.getWriter().print("失败!");
return HandlerInterceptor.super.preHandle(request, response, handler);
*/
}
/**
* 调用完controller,视图渲染之前
*
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("LoginInterceptor ==》postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 整个完成后,通常用于资源清理
*
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("LoginInterceptor ==》afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
2. 注册刚才加的LoginInterceptor,并制定拦截的路径
注解拦截器注意的地方。要么是类上面没加注解,要么就是拦截的路径设置的有问题
拦截的路径一般子在结尾的时候加** 表示所有的。/是匹配子文件夹
拦截所有可以配置为/*
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截的路径一般子在结尾的时候加** 表示所有的。/*是匹配子文件夹
//拦截所有可以配置为/**
registry.addInterceptor(new LoginInterceptor())
//制定拦截的路径
.addPathPatterns("/api/*/**")
//添加不拦截的路径
.excludePathPatterns("/login", "/css/**", "/images/**", "/js/**", "/login.html");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
3. controller的测试方法
@RequestMapping("/api/test/testLoginInterceptor")
public Object testLoginInterceptor() {
Map map = new HashMap();
map.put("test","我的拦截器");
return map;
}
拦截器的相关问题
1、@Configuration
继承WebMvcConfigurationAdapter(SpringBoot2.X之前旧版本)
SpringBoot2.X 新版本配置拦截器 implements WebMvcConfigurer
2、自定义拦截器 HandlerInterceptor
preHandle:调用Controller某个方法之前
postHandle:Controller之后调用,视图渲染之前,如果控制器Controller出现了异常,则不会执行此方法
afterCompletion:不管有没有异常,这个afterCompletion都会被调用,用于资源清理
3、按照注册顺序进行拦截,先注册,先被拦截
拦截器不生效常见问题:
1)是否有加@Configuration
2)拦截路径是否有问题 ** 和 *
3)拦截器最后路径一定要 “/**”, 如果是目录的话则是 /*/
Filter和拦截器的区别
- Filter是基于函数回调 doFilter(),而Interceptor则是基于AOP思想
- Filter在只在Servlet前后起作用,而Interceptor够深入到方法前后、异常抛出前后等
- Filter依赖于Servlet容器即web应用中,而Interceptor不依赖于Servlet容器所以可以运行在多种环境。
- 在接口调用的生命周期里,Interceptor可以被多次调用,而Filter只能在容器初始化时调用一次。
Filter和Interceptor的执行顺序
过滤前->拦截前->action执行->拦截后->过滤后