SpirngBoot中使用Interceptor拦截器
本篇文章可以带您快速复习拦截器的使用,食用本篇文章前您必须熟练掌握并拥有基于注解配置SpringMVC的能力!
1.快速回顾拦截器
首先我们需要通过以下图片回顾一下SpringMVC中拦截器的执行位置。
拦截器(
Interceptor
)是一种动态拦截方法调用的机制,在SpringMVC
中动态拦截控制器方法的执行作用:
- 在指定的方法调用前后执行预先设定的代码
- 阻止原始方法的执行
- 总结:拦截器就是用来做增强
拦截器和过滤器之间的区别
- 归属不同:
Filter
属于Servlet
技术,Interceptor
属于SpringMVC
技术 - 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
- 归属不同:
2.SpringBoot中使用拦截器
创建一个
SpringBoot
工程并勾选web开发的依赖创建完毕后我们需要编写一个
UserController
类进行测试@RestController @RequestMapping("/user") public class UserController { @GetMapping("/login") public String login(){ return "登陆成功!"; } @GetMapping("/register") public String register(HttpSession session){ //模拟用户注册,将用户信息存储session域中 session.setAttribute("user","user"); return "注册成功!"; } } java
然后我们通过浏览器访问这两个路径
/login
、/register
通过访问可以发现两个接口均可正常访问,但这显然不是我们所期望的,我们期望的是用户在没有注册的情况下直接访问登录接口是失败的,因此我们需要通过添加一个拦截器的功能来实现。
新建一个拦截器
MyInterceptor
并实现HandleInterceptor
接口@Component //将这个类放进spring的容器中 public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); //从session域中获取user Object user = session.getAttribute("user"); if (user == null){ //如果user为null,说明用户没有注册,进行拦截 response.setStatus(401); return false; } return true; } } java
新建一个
SpringMVC
的配置类SringMvcConfig
用来添加拦截器@Configuration public class SpringMvcConfig implements WebMvcConfigurer { @Resource private MyInterceptor myInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { //添加我们的拦截器,使其生效,addPathPatterns()方法是执行拦截了拦截的路径,默认拦截全部路径 registry.addInterceptor(myInterceptor).addPathPatterns("/user/login"); } } java
此时我们重启项目再次访问两个路径
3.拦截器的方法说明
我们自定义的拦截器在实现了
HandlerInterceptor
接口后我们可以选择实现三个方法
3.1 前置处理方法
控制器方法执行之前执行
preHandle()
,其boolean类型的返回值表示是否拦截或放行,返回true
为放行,即调用控制器方法。返回
false
表示拦截,即不调用控制器方法。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle()方法被执行!");
return true;
}
java
request
:请求对象response
:响应对象handler
:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
使用handler参数,可以获取方法的相关信息
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod hm = (HandlerMethod)handler;
String methodName = hm.getMethod().getName();//可以获取方法的名称
System.out.println("preHandle..."+methodName);
return true;
}
java
3.2 后置处理方法
原始方法运行后运行,如果原始方法被拦截,则不执行
@Override
public void postHandle(HttpServletRequest req, HttpServletResponse resp, Object handler, ModelAndView mv) throws Exception {
System.out.println("postHandle()方法被执行!");
}
java
前三个参数和上面的是一致的。
modelAndView
:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整因为咱们现在都是返回
json
数据,所以该参数的使用率不高。
3.3 完成处理方法
拦截器最后执行的方法,无论原始方法是否执行
@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion()方法被执行!");
}
java
前三个参数与上面的是一致的。
ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理 ,因为我们现在已经有全局异常处理器类,所以该参数的使用率也不高。
这三个方法中,最常用的是preHandle(),在这个方法中可以通过返回值来决定是否要进行放行,我们可以把业务逻辑放在该方法中,如果满足业务则返回true放行,不满足则返回false拦截。
4.多个拦截器执行顺序
目前,我们在项目中只添加了一个拦截器,如果有多个,该如何配置?配置多个后,执行顺序是什么?
- 当配置多个拦截器时,形成拦截器链
- 拦截器链的运行顺序参照拦截器添加顺序为准
- 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
- 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作
preHandle:与配置顺序相同,必定运行
postHandle:与配置顺序相反,可能不运行
afterCompletion:与配置顺序相反,可能不运行。
这个顺序不太好记,最终只需要把握住一个原则即可:以最终的运行结果为准