在 Java Web 系统开发中,不管是 Controller 层、Service 层还是 Dao 层,都有可能抛出异常。如果在每个方法中加上各种 try catch 的异常处理代码,那样会使代码非常繁琐。在Spring中,我们可以将所有类型的异常处理从各个单独的方法中解耦出来,进行异常信息的统一处理和维护。
在 Spring MVC 中全局异常捕获处理的解决方案通常有两种方式:
@ControllerAdvice + @ExceptionHandler 注解进行 Controller 层异常处理。org.springframework.webb.servlet.HandlerExceptionResolver 接口中的 resolveException 方法。由于HandlerExceptionResolver很少使用,因此这里只介绍第一种实现方式。
这种方式的好处是简单统一,但是需要在每一层都要抛出异常,保证异常能够被controller层接收。
@ControllerAdivce的组成如下:
public @interface ControllerAdvice { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class>[] basePackageClasses() default {}; Class>[] assignableTypes() default {}; Class extends Annotation>[] annotations() default {};
@ControllerAdvice 注解用于定义全局异常处理类。类中可定义多个异常处理函数,可分别处理不同的异常情况。其参数用于指定生效的范围。形式可以是包、class、注解等,默认是对全部的controller生效。
@ExceptionHandler()注解用于定义当前方法捕获处理的异常类型。当在 controller 中捕获到相应的异常类型时,就会触发当前方法的执行,进行异常处理。
被@ExceptionHandler()注解修饰的方法,一般会将该异常类型作为参数传入到方法中,从而在方法中获取异常信息并进一步处理。
@ExceptionHandler(CustomException.class)
public Result exception(CustomException e){ return new Result(false,"全局异常处理");
}
如果@ExceptionHandler所在的类是@Controller,则此方法只作用在此类。如果@ExceptionHandler所在的类带有@ControllerAdvice注解,则此方法会作用在全局。
使用@ControllerAdvice和@ExceptionHandler注解,能够细粒度的控制该异常处理器针对哪些 Controller 有效:
一个小案例如下:
package top.xcyxiaoxiang.common; /** * @Description: 全局异常处理案例 * @date: 2022/6/30 下午9:49 * @author: xcy.小相 * @ClassName : GlobalExceptionHandler */
// 指定要拦截的位置
@ControllerAdvice(annotations = {RestController.class, Controller.class})
// 设置以json的形式返回数据
@ResponseBody
// 日志记录
@Slf4j
public class GlobalExceptionHandler { /** * 帐号存在异常 * @param ex * @return */ @ExceptionHandler(SQLIntegrityConstraintViolationException.class) public R exceptionHandler(SQLIntegrityConstraintViolationException ex){ // 获取异常信息 String exMessage = ex.getMessage(); log.error("捕获到异常:{}",exMessage); // 处理异常信息 if(exMessage.contains("Duplicate entry")){ String[] msg = exMessage.split(" "); return R.error("帐号 "+msg[2]+" 已存在!"); } return R.error("未知错误!"); } }
若项目结构为 ssm 结构,那么记得将异常处理类注入到spring容器中去!
参考:
Spring Boot 全局异常处理整理!开发必会! - 知乎 (zhihu.com)
springBoot 全局异常处理 - 知乎 (zhihu.com)
SpringMVC 异常处理 SimpleMappingExceptionResolver 类 博客园 (cnblogs.com)