springBoot 全局异常统一处理
注解说明
// 对某一类异常进行统一处理, 从而能够减少代码重复率和复杂度
@ExceptionHandler
// 异常集中处理, 更好的将业务逻辑和异常处理解耦
@ControllerAdvice
// 将某种异常映射为HTTP状态码
@ResponseStatus
定义全局异常捕获类
@ControllerAdvice
public class ExceptionController {
private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionController.class);
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public AIResponse exceptionHandler(Exception exception) {
LOGGER.info("exception: " + exception.getMessage());
if (exception instanceof SQLException || exception instanceof UncategorizedSQLException) {
return AIResponse.failed("操作数据库异常");
}
return AIResponse.failed(exception.getMessage());
}
@ExceptionHandler(NullPointerException.class)
@ResponseStatus(HttpStatus.ACCEPTED)
@ResponseBody
public AIResponse exceptionHandler(NullPointerException nullPointerException) {
LOGGER.info("nullPointerException: " + nullPointerException.getMessage());
// 空指针异常需要打印堆栈信息
nullPointerException.printStackTrace();
return AIResponse.failed(nullPointerException.getMessage());
}
}
测试验证
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("query")
@ResponseBody
public AIResponse query(@RequestBody RequestDTO requestDTO) {
// ...
}
}
如果项目中采用 AOP, 则 AOP 中的异常要抛出, 不要捕获处理
@Component
@Aspect
@Slf4j
public class AALAop {
@Around("execution(public * com.answer.aal.controller..*Controller.*(..))")
public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result;
Object[] args = proceedingJoinPoint.getArgs();
result = proceedingJoinPoint.proceed(args);
/** ERROR
try {
result = proceedingJoinPoint.proceed(args);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
*/
return result;
}
}
@Slf4j
@ControllerAdvice
@ResponseBody
public class GlobalController {
// 业务捕获异常
@ExceptionHandler(BusinessException.class)
public AIResponse bsinessException(BusinessException ex, HttpServletRequest request) {
ResponseEnum responseEnum = ex.getResponseEnum();
String requestId = (String) request.getAttribute(REQUEST_UNIQUE_ID_KEY);
log.info("#{}# code:{}, msg:{}-{}",
requestId, responseEnum.code(), responseEnum.message(), ex.getMessage());
return AIResponse.failedMsg(ex.getResponseEnum(), ex.getMessage());
}
// 方法参数校验异常, @Valid @Validated
@ExceptionHandler(MethodArgumentNotValidException.class)
public AIResponse methodArgumentNotValidException(
MethodArgumentNotValidException ex,
HttpServletRequest request) {
String requestId = (String) request.getAttribute(REQUEST_UNIQUE_ID_KEY);
log.info("#{}# methodArgumentNotValidException:{}",
requestId, ex.getMessage());
return AIResponse.failedMsg(ResponseEnum.REQUEST_PARAM_ERROR,
Optional.ofNullable(ex.getBindingResult()).map(Errors::getFieldError).map(e -> e.getField() + e.getDefaultMessage()).orElse("参数错误"));
}
// 请求参数错误
@ExceptionHandler(HttpMessageNotReadableException.class)
public AIResponse httpMessageNotReadableException(
HttpMessageNotReadableException ex,
HttpServletRequest request) {
String requestId = (String) request.getAttribute(REQUEST_UNIQUE_ID_KEY);
log.info("#{}# httpMessageNotReadableException:{}",
requestId, ex.getMessage());
return AIResponse.failedMsg(ResponseEnum.REQUEST_PARAM_ERROR, "请求参数类型错误");
}
// 请求方法GET/POST...不支持
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public AIResponse httpRequestMethodNotSupportedException(
HttpRequestMethodNotSupportedException ex,
HttpServletRequest request) {
String requestId = (String) request.getAttribute(REQUEST_UNIQUE_ID_KEY);
log.info("#{}# method={}, supportedHttpMethods={},httpRequestMethodNotSupportedException:{}",
requestId, ex.getMethod(), ex.getSupportedHttpMethods(), ex.getMessage());
return AIResponse.failedMsg(ResponseEnum.REQUEST_METHOD_ERROR, ex.getMessage());
}
@ExceptionHandler(Exception.class)
public AIResponse exception(Exception ex, HttpServletRequest request) {
String requestId = (String) request.getAttribute(REQUEST_UNIQUE_ID_KEY);
log.error("#" + requestId + "# exception:", ex);
return AIResponse.failedMsg(ResponseEnum.SERVICE_ERROR, ex.getMessage());
}
}