SpringMVC提供了统一处理Controller层抛出的异常的方法
RestController的统一异常处理
- package com.lan.controller;
-
- import com.lan.exception.BusinessException;
- import com.lan.exception.SystemException;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.RestControllerAdvice;
-
- //注解@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
- @RestControllerAdvice
- public class ProjectExceptionAdvice {
- //注解@ExceptionHandler用于设置当前处理器类对应的异常类型
- @ExceptionHandler(SystemException.class) // 处理SystemException
- public Result doSystemException(SystemException ex){
- //记录日志
- //发送消息给运维
- //发送邮件给开发人员,ex对象发送给开发人员
- // ...
- return new Result(ex.getCode(),null,ex.getMessage());
- }
-
- @ExceptionHandler(BusinessException.class) // 处理BusinessException
- public Result doBusinessException(BusinessException ex){
- // ...
- return new Result(ex.getCode(),null,ex.getMessage());
- }
-
- //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
- @ExceptionHandler(Exception.class) // 处理其它的Exception
- public Result doOtherException(Exception ex){
- // ...
- return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
- }
- }
| 注解 | 作用 | 作用目标 |
| @RestControllerAdvice | 为Controller类做增强,相当于@ControllerAdvice+@ResponseBody,@ExceptionHandler 方法默认带有 @ResponseBody 。 | 类 |
| @ExceptionHandler | 设置指定类型异常的处理方案,Controller出现指定类型的异常后转入当前方法执行 | 方法 |
通过@RestControllerAdvice增强Controller的同时,实现ResponseBodyAdvice接口可以统一封装RestController的返回结果。
案例如下:
- package com.lan.controller;
-
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.core.MethodParameter;
- import org.springframework.http.MediaType;
- import org.springframework.http.converter.HttpMessageConverter;
- import org.springframework.http.server.ServerHttpRequest;
- import org.springframework.http.server.ServerHttpResponse;
- import org.springframework.web.bind.annotation.RestControllerAdvice;
- import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
-
- import com.fasterxml.jackson.core.JsonProcessingException;
- import com.fasterxml.jackson.databind.ObjectMapper;
-
- @RestControllerAdvice
- public class ResponseHandler implements ResponseBodyAdvice
- @Autowired
- private ObjectMapper objectMapper;
-
- @Override
- public boolean supports(MethodParameter returnType, Class extends HttpMessageConverter>> converterType) {
- // 类型不是Result时使用增强
- if(returnType.getParameterType() != Result.class) {
- return true;
- }
- return false;
- }
-
- // body为原返回对象
- @Override
- public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
- Class extends HttpMessageConverter>> selectedConverterType, ServerHttpRequest request,
- ServerHttpResponse response) {
- try {
- return objectMapper.writeValueAsString(new Result(0, body));
- } catch (JsonProcessingException e) {
- e.printStackTrace();
- }
- return body;
- }
- }
SpringMVC中的拦截器(interceptor)是一种动态拦截控制层的机制,用来做控制层增强。

归属不同:Filter属于Serlvet技术,Interceptor属于SpringMVC技术。
拦截范围不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强。
Servlet配置类
- package com.lan.config;
-
- import org.springframework.web.filter.CharacterEncodingFilter;
- import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
-
- import javax.servlet.Filter;
-
- public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
- protected Class>[] getRootConfigClasses() {
- // return new Class[SpringConfig.class];
- return new Class[0];
- }
-
- protected Class>[] getServletConfigClasses() {
- return new Class[]{SpringMvcConfig.class};
- }
-
- protected String[] getServletMappings() {
- return new String[]{"/"}; // 表示SpringMVC要处理的所有路径
- }
-
- //乱码处理的过滤器Filter
- @Override
- protected Filter[] getServletFilters() {
- CharacterEncodingFilter filter = new CharacterEncodingFilter();
- filter.setEncoding("UTF-8");
- return new Filter[]{filter};
- }
- }
拦截器
- package com.lan.controller.interceptor;
-
- import org.springframework.stereotype.Component;
- import org.springframework.web.method.HandlerMethod;
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- @Component
- //定义拦截器类,实现HandlerInterceptor接口
- //注意当前类必须受Spring容器控制
- public class ProjectInterceptor implements HandlerInterceptor {
- @Override
- //原始方法调用前执行的内容
- //返回值类型可以拦截控制的执行,true放行,false终止
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- String contentType = request.getHeader("Content-Type");
- HandlerMethod hm = (HandlerMethod)handler;
- System.out.println("preHandle..."+contentType);
- 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...");
- }
- }
拦截器配置类(注意:拦截器类要被SpringMVC容器扫描到):
- package com.lan.config;
-
- import com.itheima.controller.interceptor.ProjectInterceptor;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
- import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
- import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
-
- @Configuration
- public class SpringMvcSupport extends WebMvcConfigurationSupport {
- @Autowired
- private ProjectInterceptor projectInterceptor;
-
- @Override
- protected void addResourceHandlers(ResourceHandlerRegistry registry) {
- // 不需要SpringMVC处理的静态资源
- registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
- }
-
- @Override
- protected void addInterceptors(InterceptorRegistry registry) {
- //配置拦截器和拦截的所有路径
- registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
- // 添加多个添加拦截器
- // registry.addInterceptor(xxx).addPathPatterns("/xxx","/xxx/*");
- }
- }