看完这篇,SpringBoot再也不用写try/catch了
前言
使用 SpringBoot 开发 Web 应用时,异常处理是必不可少的一部分。在应用中,异常可能会出现在任何地方,例如在控制器、服务层、数据访问层等等。如果不对异常进行处理,可能会导致应用崩溃或者出现未知的错误。因此,对于异常的处理是非常重要的。
本篇主要讲述在SpringBoot 中,如何用全局异常处理优雅的处理异常。
为什么要优雅的处理异常
如果我们不统一的处理异常,开发人员经常会在代码中东一块的西一块的写上 try catch代码块,长久以往容易堆积成屎山。
@Slf4j
@Api(value = "User Interfaces", tags = "User Interfaces")
@RestController
@RequestMapping("/user")
public class UserController {
/**
* @param userParam user param
* @return user
*/
@ApiOperation("Add User")
@ApiImplicitParam(name = "userParam", type = "body", dataTypeClass = UserParam.class, required = true)
@PostMapping("add")
public ResponseEntity add(@Valid @RequestBody UserParam userParam) {
// 每个接口都需要手动try catch
try {
// do something
} catch(Exception e) {
return ResponseEntity.fail("error");
}
return ResponseEntity.ok("success");
}
}
那我们应该如何实现统一的异常处理呢?
使用 @ControllerAdvice + @ExceptionHandler注解
@ControllerAdvice 定义该类为全局异常处理类
@ExceptionHandler 定义该方法为异常处理方法。value 的值为需要处理的异常类的 class 文件。
首先自定义异常类 BusinessException :
/**
* 业务异常类
* @author rango
*/
@Data
public class BusinessException extends RuntimeException {
private String code;
private String msg;
public BusinessException(String code, String msg) {
this.code = code;
this.msg = msg;
}
}
然后编写全局异常类,用 @ControllerAdvice
注解:
/**
* 全局异常处理器
* @author rango
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 处理 Exception 异常
* @param httpServletRequest httpServletRequest
* @param e 捕获异常
* @return
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public ResponseEntity exceptionHandler(HttpServletRequest httpServletRequest, Exception e) {
logger.error("服务错误:", e);
return new ResponseEntity("******", "服务出错");
}
/**
* 处理 BusinessException 异常
* @param httpServletRequest httpServletRequest
* @param e 捕获异常
* @return
*/
@ResponseBody
@ExceptionHandler(value = BusinessException.class)
public ResponseEntity businessExceptionHandler(HttpServletRequest httpServletRequest, BusinessException e) {
logger.info("业务异常报错!code:" + e.getCode() + "msg:" + e.getMsg());
return new ResponseEntity(e.getCode(), e.getMsg());
}
}
定义了全局异常处理器,项目就可以对不同的异常进行统一处理了。通常,为了使 controller 中不再使用任何 try/catch
,会在 GlobalExceptionHandler
中对 Exception
做统一的拦截处理。这样其他没有用 @ExceptionHandler
配置的异常就都会统一被处理。
遇到异常时主动抛出异常
在业务中,遇到业务异常的地方,我们直接 throw 抛出对应的业务异常即可。如下所示
throw new BusinessException(ERROR_CODE, "用户账号/密码有误");
在 Controller 中的写法
Controller 中,不需要再写 try/catch
,除非特殊场景。
@RequestMapping(value = "/test")
public ResponseEntity test() {
ResponseEntity re = new ResponseEntity();
// 业务处理
return re;
}
结果展示
异常抛出后,返回如下结果。
{
"code": "E0014",
"msg": "用户账号/密码有误",
"data": null
}
注意!!!
抛出的异常如果被代码内的try/catch
捕获了,就不会被GlobalExceptionHandler
处理
异步方法中的异常不会被全局异常处理(多线程)
不是 controller 层抛出的异常才能被GlobalExceptionHandler
处理,只要异常最后是从 contoller 层抛出去的都可以被捕获并处理
总结
本文介绍了使用 SpringBoot 时,如何通过配置全局异常处理器统一处理项目中的一些通用的异常,避免程序员不断的写try/catch导致的代码冗余,有利于代码的维护。
作者:程序员典籍
来源:mdnice.com/writing/103055f00ba04cf4b06f0195f839a449
来源:mdnice.com/writing/103055f00ba04cf4b06f0195f839a449