应用场景
- 权限检查:检查是否有访问某接口的权限;
- 日志记录:记录请求信息的日志,便于进行信息监控与统计;
- 性能检测:慢日志等记录时间的场景;
如何实现拦截器
拦截器接口
public interface HandlerInterceptor {
/**
* 预处理回调方法,预处理
* @param request 请求
* @param response 响应
* @param handler 响应的处理器,自定义Controller
* @return 返回true则流程继续,返回false则流程中断,此时需要通过response参数产生响应
* @throws Exception
*/
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
/**
* 后处理回调方法,前后端不分离环境下可以通过modelAndView对模型数据进行处理
* @param request 请求
* @param response 响应
* @param handler 自定义处理器
* @param modelAndView 视图
* @throws Exception
*/
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
/**
* 整个接口的处理完毕回调函数,该函数内部可以进行处理链中资源的回收,或者记录
* 该接口所耗费的时间,进行性能检测
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
这三个方法在MVC结构中可以简单理解为:
- Controller前(preHandle)
- Controller后(postHandle)
- 接口完全处理完毕(afterCompletion)
拦截器接口实现实例
实现一个拦截器的主要步骤有三步:
- 编写类实现HandlerInterceptor接口
- 编写配置类实现WebMvcConfigurer接口注册拦截器
- 指定需要拦截的路径与放行的路径
一、实现HandlerInterceptor接口
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @ClassName InterceptorDemo
* @Description 实现HandlerInterceptor接口
* @Author 黄乙轩
* @Date 2021/6/20 10:31
* @Version 1.0
**/
public class InterceptorDemo implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
System.out.println(handler);
String id = request.getParameter("id");
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");
}
}
二、编写配置类
/**
* @ClassName InterceptorConfig
* @Description 编写配置类注册拦截器
* @Author 黄乙轩
* @Date 2021/6/20 10:36
* @Version 1.0
**/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration registration = registry.addInterceptor(new InterceptorDemo());
}
}
这里需要注意一点,就是拦截器的运行顺序是按照注册的顺序执行的。
三、指定拦截路径与放行路径
这里我们假设我们需要拦截所有的请求,除了login请求不进行拦截。
/**
* @ClassName InterceptorConfig
* @Description 编写配置类注册拦截器
* @Author 黄乙轩
* @Date 2021/6/20 10:36
* @Version 1.0
**/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration registration = registry.addInterceptor(new InterceptorDemo());
registration
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
这样一个简单的拦截器就完成了。
我们来开启服务来进行一下简单的测试。
Demo展示
/**
* @ClassName Controller
* @Description Controller类
* @Author 黄乙轩
* @Date 2021/6/20 10:38
* @Version 1.0
**/
@CrossOrigin
@RestController
public class Controller {
@RequestMapping("/demo")
public void demo(@RequestParam("id")String id){
System.out.println("id:"+id);
System.out.println("demo");
}
@RequestMapping("/login")
public void login(){
System.out.println("login");
}
}
利用Postman进行测试;
先来进行demo接口的测试:
在进行 login 接口的测试:
可以看到并没有进行拦截;
可以观测到后端的响应顺序是:
preHandler => controller => postHandle => afterCompletion
如此一个简单的拦截器就完成了;
一些SpringBoot中使用拦截器的坑点
拦截器中无法自动注入
场景:在一次写项目的过程中,使用到了拦截器以及单点登录;我想现在后端拦截器中进行权限查询,但是我发现他不能进行自动注入,@Autowired 之后对象为空。
原因:我们可以看到这个地方:
我们是通过new来创建的对象,而在SpringBoot中并不会把new创建的对象当做bean进行管理。
解决方法:通过构造注入与@Bean注解进行管理,同时记得给拦截器加上@Component注解
例:
@Bean
public InterceptorDemo getInterceptorDemo(){
return new InterceptorDemo();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration registration = registry.addInterceptor(getInterceptorDemo());
registration
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
总结
拦截器的应用场景很多,而且在SpringBoot中十分重要,其操作其实十分简单,主要是实现 HandlerInterceptor 接口以及编写配置类。