1. 自定义异常处理@ControllerAdvice/@RestControllerAdvice
- @ControllerAdvice/@RestControllerAdvice可以处理Controller层类抛出来的异常。
- @ControllerAdvice与@RestControllerAdvice区别类似于@RestController 与 @Controller的区别
@ControllerAdvice
public class ControllerExceptionHandler {
private static final String UNKNOWN_ERROR_CODE = "-1";
public static final String DEFAULT_ERROR_VIEW = "error";
private final static Logger LOGGER =
LoggerFactory.getLogger(ControllerExceptionHandler.class);
@ExceptionHandler(value = PageException.class)
public ModelAndView businessExceptionHandler(HttpServletRequest req, Exception e) throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("message", e.getMessage());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
/**
* 预期异常内容处理
* @param e
* @return
*/
@ExceptionHandler(value = ExpectedException.class)
@ResponseBody
public BasicResponseVo expectedExceptionResolver(ExpectedException e) {
LOGGER.error("系统发生{}异常, 异常信息{}:", e.getExceptionCause(), exceptionCodeConfig.getMapperMsg(e.getExceptionCause()), e);
return builder(e);
}
private BasicResponseVo builder(Exception e) {
BasicResponseVo responseVo = new BasicResponseVo();
responseVo.setResponseTime(LocalDateTime.now());
if(e instanceof ExpectedException){
responseVo..setRespCode(e.getExceptionCause().getCode());
responseVo.etRespDesc(e.getExceptionCause().getMessage());
}else{
responseVo.setRespCode(UNKNOWN_ERROR_CODE);
responseVo.etRespDesc(e.getClass().getName());
}
return responseVo;
}
}
2. 全局异常处理 BasicErrorController
BasicErrorController是spring-boot默认统一的全局异常类,这个类提供了默认了错误处理方法,包括错误跳转的路径和渲染方法。BasicErrorController会根据根据Accept头的内容,输出不同格式的错误响应当你是页面请求的时候就会返回页面,另外一种是json请求的时候就会返回json错误
org.springframework.boot.autoconfigure.web.servlet.errorBasicErrorController部分源码
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null ? modelAndView : new ModelAndView("error", model));
}
@RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<>(body, status);
}
BasicErrorController会默认返回error页面或固定格式格式为json,所以如果项目使用就必须重新实现BasicErrorController类。
重写CustomErrorController
/**
* @see org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController
* @see org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
* Created by Mr.J on 2018/1/20.
*/
@Controller
public class CustomErrorController extends BasicErrorController {
@Autowired
public CustomErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties) {
super(errorAttributes, serverProperties.getError());
}
public CustomErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
super(errorAttributes, errorProperties, errorViewResolvers);
}
/**
* 覆盖默认的Json响应
*/
@Override
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
BasicResponseVo body = this.buildBody(request, this.isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = HttpStatus.OK;
// HttpStatus status = this.getStatus(request);
return new ResponseEntity(body, status);
}
/**
* 覆盖默认的HTML响应
*/
@Override
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
//请求的状态
HttpStatus status = getStatus(request);
response.setStatus(getStatus(request).value());
Map<String, Object> model = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.TEXT_HTML));
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
//指定自定义的视图
return(modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
private BasicResponseVo buildBody(HttpServletRequest request, Boolean includeStackTrace){
Map<String,Object> errorAttributes = getErrorAttributes(request, includeStackTrace);
String message = String.format("Requested path %s with result %s", errorAttributes.get("path"), errorAttributes.get("message"));
String trace ="";
BasicResponseVo responseVo = new BasicResponseVo();
responseVo.setResponseTime(LocalDateTime.now());
responseVo.setRespCode((String)errorAttributes.get("status"));
responseVo.setRespDesc(message);
responseVo.setTrace((String)errorAttributes.get("trace"))
return responseVo;
}
继承于BasicErrorController,注意一定要添加@Controller,不然Spring无法感知自定义的bean,BasicErrorController还是会起作用。至于新的Controller如何替换BasicErrorController关键在spring boot 在ErrorMvcAutoConfiguration自动装载BasicErrorController Bean的时候使用了@ConditionalOnMissingBean注解。
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
this.errorViewResolvers);
}