全局异常处理
@ControllerAdvice注解:
- 不写参数:所有Controller参数为包名:包下的所有Controller,可指定多个如:
@ControllerAdvice(basePackages={"cn.ken.test1", "cn.ken.test2"})参数为注解:可以自定义注解后匹配所有加了该注解的Controller,如:@ControllerAdvice(annotations={MyAnnotation.class})
此注解是一个在类上声明的注解,是aop思想的一种实现,主要通过配合@ExceptionHandler、@InitBinder 或 @ModelAttribute这三个注解以实现全局异常处理、全局数据绑定和全局数据预处理
@ExceptionHandler注解指定要捕获的异常类型
@ControllerAdvice public class AllControllerAdvice { private static Logger logger = LoggerFactory.getLogger(AllControllerAdvice.class); /** * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器 */ @InitBinder public void initBinder(WebDataBinder binder) { } /** * 把值绑定到Model中,使全局@RequestMapping可以获取到该值 */ @ModelAttribute public void addAttributes(Model model) { } /** * 捕捉shiro的异常 * @param e * @return */ @ResponseStatus(HttpStatus.OK) @ExceptionHandler(ShiroException.class) @ResponseBody public ResponseModel<String> handleShiroException(ShiroException e) { return ResponseHelper.failedWith(null, CodeEnum.IDENTIFICATION_ERROR.getCode(),CodeEnum.IDENTIFICATION_ERROR.getMsg()); } @ResponseStatus(HttpStatus.OK) @ExceptionHandler(AuthenticationException.class) @ResponseBody public ResponseModel<String> handleShiroException(AuthenticationException e) { return ResponseHelper.failedWith(null, CodeEnum.IDENTIFICATION_ERROR.getCode(),CodeEnum.IDENTIFICATION_ERROR.getMsg()); } /** * 捕捉BusinessException自定义抛出的异常 * @return */ @ResponseStatus(HttpStatus.OK) @ExceptionHandler(BusinessException.class) @ResponseBody public ResponseModel handleBusinessException(BusinessException e) { String message = e.getMessage(); if(message.indexOf(":--:") > 0){ String[] split = message.split(":--:"); return ResponseHelper.failedWith(null,split[1],split[0]); } return ResponseHelper.failedWith(null,CodeEnum.DATA_ERROR.getCode(),message); } @ResponseStatus(HttpStatus.OK) @ExceptionHandler(TemplateInputException.class) @ResponseBody public ResponseModel<String> handleTemplateInputException(TemplateInputException e) { return ResponseHelper.failed2Message(CodeEnum.USER_NO_PERMITION.getMsg()); } @ResponseStatus(HttpStatus.OK) @ExceptionHandler(value = ParamJsonException.class) @ResponseBody public ResponseModel<String> handleParamJsonException(Exception e) { if(e instanceof ParamJsonException) { logger.info("参数错误:"+e.getMessage()); return ResponseHelper.failed2Message("参数错误:"+ e.getMessage()); } return ResponseHelper.failedWith(null,CodeEnum.PARAM_ERROR.getCode(),e.getMessage()); } @ResponseStatus(HttpStatus.OK) @ExceptionHandler(value = HttpMessageNotReadableException.class) @ResponseBody public ResponseModel<String> handleParamJsonException(HttpMessageNotReadableException e) { if(e instanceof HttpMessageNotReadableException) { logger.info("参数错误:"+e.getMessage()); return ResponseHelper.failed2Message("参数错误:"+ e.getMessage()); } return ResponseHelper.failedWith(null,CodeEnum.PARAM_ERROR.getCode(),e.getMessage()); } /** * 全局异常捕捉处理 */ @ResponseBody @ExceptionHandler(value = Exception.class) @ResponseStatus(HttpStatus.OK) public ResponseModel<String> errorHandler(Exception ex) { ex.printStackTrace(); logger.error("接口出现严重异常:{}", ex.getMessage()); return ResponseHelper.failed2Message(CodeEnum.ERROR.getMsg()); } }
可在类下定义多个@ExceptionHandler以对不同异常进行不同的处理
ExceptionHandler的处理顺序是由异常匹配度来决定的,首先找到可以匹配异常的所有ExceptionHandler,然后对其进行排序(深度比较器,通过递归不停地判断父异常是否为目标异常来取得最终的深度),取深度最小,即匹配度最高的那个