拦截器接口HandlerInterceptor
HandlerInterceptor中的方法方法
public interface HandlerInterceptor {
//具体handler执行前的拦截器,boolean返回是否进行拦截
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
//handler正常执行完后的逻辑,不实现拦截,可以对modelAndView操作。
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
//拦截器放行后必定执行该方法,可能正常执行,可能异常捕获执行。
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
执行流程
MVC执行流程中拦截器为我们提供方法的执行位置
try{
ModelAndView mv = null;
Object dispatchException = null;
try{
/**
......
*/
//前置拦截器返回false,return
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//执行具体的handler方法逻辑
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
/**
........
*/
//执行后置拦截器,传入modelAndView
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
//无异常正常执行afterCompletion
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
}
//出现异常捕获执行aferComletion
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
}
注意!
前后端分离项目,controller返回Json对象时,执行handler.handle时,前端调用已经结束,结果已经返回,此时modelAndView为空
Demo验证
Controller.java
接口测试
@RestController
@RequestMapping("/fht")
public class LoginController {
@GetMapping("exception")
public String exception(){
int i = 10/0;
return "exception";
}
@GetMapping("false")
public String falseTest(){
return "false";
}
@GetMapping("normal")
public String normal() {
return "normal";
}
MyInterceptor.java
我们自己的拦截器,需要实现HandlerInterceptor接口。
/**
自定义拦截器,实现HandlerInterceptor接口
*/
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
/**
测试只拦截URI为false的请求
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("拦截器preprepre执行");
if (handler instanceof HandlerMethod && "/fht/false".equals(request.getRequestURI())) {
HandlerMethod my = (HandlerMethod) handler;
log.info("被拦截");
return false;
}
return true;
}
/**
测试查看modelAndView内容
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("拦截器postpostpost执行");
log.info("modelAndView是:{}", modelAndView);
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
异常不验证了,一般异常都被捕获,这里都为null
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("===afterCompletion,执行");
if(ex ==null){
log.info("无异常");
}else {
log.info("异常:{}",ex.getMessage());
}
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
MyMvcConfig.java
将我们的拦截器注册到MVC的容器中,需要实现WebMvcConfigurer,重写addInterceptors
/**
自定义MVC配置类添加自定义MyInterceptor拦截器。
*/
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Bean
public HandlerInterceptor handlerInterceptor(){
return new MyInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration interceptor = registry.addInterceptor(handlerInterceptor());
//配置拦截路径,不配置默认为 **,拦截所有
interceptor.addPathPatterns("/fht/**")
//不拦截路径
.excludePathPatterns("/fht/test");
}
}
验证执行流程
1.正常执行不拦截
-
URL: http://localhost:8080/fht/test
-
打印结果:
结论: pre ->post ->after
2.被拦截
- URL: http://localhost:8080/fht/false
- 打印结果:
结论: 只执行pre
3.出现异常被全局捕获
- **URL:**http://localhost:8080/fht/exception
- 打印结果:
结论:不执行post,异常被全局异常处理,afterCompletion 中传入的 Exception 为 null
MVC执行流程中返回结果的处理
preHadnler 和 postHandler打断点,debug运行后输入URL,在 preHandle 断点时浏览器在等结果,在 postHandle 时,结果已经返回,此时modelAndView是空的,结果已经被 JSON 处理器处理通过response.flush返回给客户端了。