Spring 统一异常处理
非统一异常处理
在传统的非统一异常处理方式中,每个代码块都需要单独编写 try...catch... 语句来捕获异常,例如:
A代码: try...catch...B代码: try...catch...C代码: try...catch...D代码: try...catch...
这种方式会导致代码冗余,并且难以维护。
统一异常处理
在 Spring 中,我们可以使用 AOP(面向切面编程)的思想来实现异常的统一处理。核心是利用 Spring 提供的两个注解 @RestControllerAdvice 和 @ExceptionHandler。
任务步骤
整个统一异常处理的任务主要分为以下几个步骤:
- 自定义统一异常类 
BizException:规范异常类型,方便ExceptionHandler进行处理。 - 前置异常捕获:对 
controller进行切面编程,实现对BindingResult(即调用者请求参数)的统一异常/校验处理。 - 业务异常捕获:对 
service进行切面编程,捕获所有的service异常,统一封装为BizException,再返回给controller,便于RestControllerAdvice和ExceptionHandler处理异常类型。 - 全局异常处理器:在全局异常处理器中,也就是 
RestControllerAdvice和ExceptionHandler的处理方法中,封装响应结果并返回给调用者。 
关键代码
依赖包
在 pom.xml 中添加以下依赖:
javax.validationvalidation-api2.0.1.Finalorg.springframework.bootspring-boot-starter-validationorg.springframework.bootspring-boot-starter-aoporg.springframework.bootspring-boot-starter-weborg.projectlomboklomboktrue
统一异常定义
自定义 BizException 类,继承自 RuntimeException:
public class BizException extends RuntimeException {private String code;private String msg;public BizException(String code, String msg) {this.code = code;this.msg = msg;}public String getCode() {return code;}public String getMsg() {return msg;}}
前置异常捕获
创建 ControllerAspect 类,对 controller 进行切面编程:
/*** 前置异常切面*/@Aspect@Componentpublic class ControllerAspect {private static final Logger log = LoggerFactory.getLogger(ControllerAspect.class);@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)" +"&&args(..,org.springframework.validation.BindingResult)")public void controllerAspect() {}@Around("controllerAspect()")public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {Object[] args = joinPoint.getArgs();for (Object arg : args) {if (arg instanceof BindingResult) {BindingResult result = (BindingResult) arg;if (result.hasErrors()) {log.error("请求参数校验错误");FieldError fieldError = result.getFieldError();if (fieldError != null) {throw new BizException("111111", fieldError.getDefaultMessage());}throw new BizException("222222", "未知参数错误┭┮﹏┭┮");}}}return joinPoint.proceed();}}
业务异常捕获
创建 ServiceAspect 类,对 service 进行切面编程:
/*** Service异常捕获,将Service中的所有异常,转换为统一的BizException,方便ExceptionHandler统一处理*/@Aspectpublic class ServiceAspect {@Pointcut("execution(public * com.example.exception.service.*.*(..))")public void serviceAspect() {}@Around("serviceAspect()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {try {return joinPoint.proceed();} catch (Exception e) {if (e instanceof BizException) {throw e;} else {throw new BizException("999999", "系统错误^_^");}}}}
全局异常处理器
创建 GlobalExceptionHandler 类,处理全局异常:
@RestControllerAdvicepublic class GlobalExceptionHandler {private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);/*** 业务异常处理*/@ExceptionHandler(BizException.class)public ResponseEntity bizExceptionHandler(BizException e) {return ResponseUtil.fail(e);}/*** 通用异常处理*/@ExceptionHandler(Exception.class)public ResponseEntity exceptionHandler(Exception e) {log.error(e.getMessage(), e);return ResponseUtil.fail("999999", "系统错误(#^.^#)");}}
通过以上步骤和代码,我们可以实现 Spring 中的统一异常处理,提高代码的可维护性和可读性。
