基于 HandlerInterceptor接口 实现的样例:
public class CustomHandlerInterceptor implements HandlerInterceptor { private static final Logger logger = LoggerFactory.getLogger(CustomHandlerInterceptor.class); /* * Controller方法调用前,返回true表示继续处理 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod method = (HandlerMethod) handler; logger.info("CustomerHandlerInterceptor preHandle, {}", method.getMethod().getName()); return true; } /* * Controller方法调用后,视图渲染前 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerMethod method = (HandlerMethod) handler; logger.info("CustomerHandlerInterceptor postHandle, {}", method.getMethod().getName()); response.getOutputStream().write("append content".getBytes()); } /* * 整个请求处理完,视图已渲染。如果存在异常则Exception不为空 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerMethod method = (HandlerMethod) handler; logger.info("CustomerHandlerInterceptor afterCompletion, {}", method.getMethod().getName()); } }除了上面的代码实现,还不要忘了将 Interceptor 实现进行注册:
@Configuration public class InterceptConfig extends WebMvcConfigurerAdapter { // 注册拦截器 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new CustomHandlerInterceptor()).addPathPatterns("/intercept/**"); super.addInterceptors(registry); }推荐指数
4颗星,HandlerInterceptor 来自SpringMVC框架,基本可代替 Filter 接口使用;
除了可以方便的进行异常处理之外,通过接口参数能获得Controller方法实例,还可以实现更灵活的定制。
@ExceptionHandler 的用途是捕获方法执行时抛出的异常,
通常可用于捕获全局异常,并输出自定义的结果。
如下面的实例:
@ControllerAdvice(assignableTypes = InterceptController.class) public class CustomInterceptAdvice { private static final Logger logger = LoggerFactory.getLogger(CustomInterceptAdvice.class); /** * 拦截异常 * * @param e * @param m * @return */ @ExceptionHandler(value = { Exception.class }) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody public String handle(Exception e, HandlerMethod m) { logger.info("CustomInterceptAdvice handle exception {}, method: {}", e.getMessage(), m.getMethod().getName()); return e.getMessage(); } }需要注意的是,@ExceptionHandler 需要与 @ControllerAdvice配合使用
其中 @ControllerAdvice的 assignableTypes 属性指定了所拦截类的名称。
除此之外,该注解还支持指定包扫描范围、注解范围等等。
推荐指数
5颗星,@ExceptionHandler 使用非常方便,在异常处理的机制上是首选;
目前也是SpringBoot 框架最为推荐使用的方法。
RequestBodyAdvice、ResponseBodyAdvice 相对于读者可能比较陌生,
而这俩接口也是 Spring 4.x 才开始出现的。
我们都知道,SpringBoot 中可以利用@RequestBody这样的注解完成请求内容体与对象的转换。
而RequestBodyAdvice 则可用于在请求内容对象转换的前后时刻进行拦截处理,其定义了几个方法:
supports 判断是否支持
handleEmptyBody 当请求体为空时调用
beforeBodyRead 在请求体未读取(转换)时调用
afterBodyRead 在请求体完成读取后调用
实现代码如下:
@ControllerAdvice(assignableTypes = InterceptController.class) public class CustomRequestAdvice extends RequestBodyAdviceAdapter { private static final Logger logger = LoggerFactory.getLogger(CustomRequestAdvice.class); @Override public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { // 返回true,表示启动拦截 return MsgBody.class.getTypeName().equals(targetType.getTypeName()); } @Override public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { logger.info("CustomRequestAdvice handleEmptyBody"); // 对于空请求体,返回对象 return body; } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException { logger.info("CustomRequestAdvice beforeBodyRead"); // 可定制消息序列化 return new BodyInputMessage(inputMessage); } @Override public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { logger.info("CustomRequestAdvice afterBodyRead"); // 可针对读取后的对象做转换,此处不做处理 return body; }