Spring Boot统一异常处理方案示例

一、异常处理的原则
1、调用方法的时候返回布尔值来代替返回null,这样可以 NullPointerException。由于空指针是java异常里最恶心的异常。
2、 catch块里别不写代码。空catch块是异常处理里的错误事件,因为它只是捕获了异常,却没有任何处理或者提示。通常你起码要打印出异常信息,当然你最好根据需求对异常信息进行处理。
3、能抛受控异常(checked Exception)就尽量不抛受非控异常(unchecked Exception[Error或者RuntimeException的异常])。通过去掉重复的异常处理代码,可以提高代码的可读性。
4、 绝对不要让你的数据库相关异常显示到客户端。由于绝大多数数据库和SQLException异常都是受控异常,在Java中,你应该在DAO层把异常信息处理,然后返回处理过的能让用户看懂并根据异常提示信息改正操作的异常信息。
5、 在Java中,一定要在数据库连接,数据库查询,流处理后,在finally块中调用close()方法。
二、示例说明
本示例以“前后端分离模式”进行演示,调试用的异常信息通过日志的形式打印出来,代码并不完整,仅从异常处理进行部分代码示例。
1、创建异常类
Spring Boot统一异常处理方案示例
文章图片

1 @Getter //通过lombok插件实现省写setter或者getter方法 2 public class SellException extends RuntimeException { 3 4private Integer code; 5private String message; 6 7public SellException(ResultEnum resultEnum) { 8super(resultEnum.getMessage()); 9this.code = resultEnum.getCode(); 10} 11 12public SellException(Integer code,String message) { 13this.code = code; 14this.message = message; 15} 16 }

【Spring Boot统一异常处理方案示例】Spring Boot统一异常处理方案示例
文章图片

2、使用Handler类捕获异常,统一格式返回给前端
Spring Boot统一异常处理方案示例
文章图片

1 @ControllerAdvice 2 public class SellExceptionHandler { 3 4@ExceptionHandler(value = https://www.it610.com/article/SellException.class) 5@ResponseBody 6public ResultVO handlerSellerException(SellException e){ 7return ResultVOUtil.error(e.getCode(),e.getMessage()); 8} 9 10 }

Spring Boot统一异常处理方案示例
文章图片

统一格式类:
Spring Boot统一异常处理方案示例
文章图片

1 public class ResultVOUtil { 2 3public static ResultVO success(Object object) { 4ResultVO resultVO = new ResultVO(); 5resultVO.setData(object); 6resultVO.setCode(0); 7resultVO.setMsg("成功"); 8return resultVO; 9} 10 11public static ResultVO success() { 12return success(null); 13} 14 15public static ResultVO error(Integer code,String msg) { 16ResultVO resultVO = new ResultVO(); 17resultVO.setCode(code); 18resultVO.setMsg(msg); 19return resultVO; 20} 21 22 }

Spring Boot统一异常处理方案示例
文章图片

Spring Boot统一异常处理方案示例
文章图片

1 @Data 2 public class ResultVO implements Serializable{ 3 4private static final long serialVersionUID = 8960474786737581150L; 5 6/** 7* 错误码 8*/ 9private Integer code; 10/** 11*提示信息 12*/ 13private String msg; 14/** 15* 具体内容 16*/ 17private T data; 18 19 }

Spring Boot统一异常处理方案示例
文章图片

3、异常的信息通过枚举统一定义,方便定义管理
Spring Boot统一异常处理方案示例
文章图片

1 @Getter 2 public enum ResultEnum { 3 4SUCCESS(0,"成功"), 5 6PARAM_ERROR(1,"参数不正确"), 7 8PRODUCT_NOT_EXIST(10,"商品不存在"), 9 10PRODUCT_STOCK_ERROR(11,"商品库存不正确"), 11 12ORDER_NOT_EXIST(12,"订单不存在"), 13 14ORDERDETAIL_NOT_EXIST(13,"订单详情不存在"), 15 16ORDER_STATUS_ERROR(14,"订单状态不正确"), 17 18ORDER_UPDATE_FAIL(15,"订单更新失败"), 19 20ORDER_DETAIL_EMPTY(16,"订单详情为空"), 21 22CART_EMPTY(18,"购物车为空"), 23 24ORDER_OWNER_ERROR(19,"该订单不属于当前用户"), 25; 26 27private Integer code; 28private String message; 29 30ResultEnum(Integer code, String message) { 31this.code = code; 32this.message = message; 33} 34 35 }

Spring Boot统一异常处理方案示例
文章图片

4、使用异常类
① controller层处理页面传来参数的校验,如参数不正确,抛出自定义异常,由handler捕获返回给页面。
Spring Boot统一异常处理方案示例
文章图片

1 @RestController 2 @RequestMapping("/buyer/order") 3 @Slf4j 4 public class BuyerOrderController { 5 6@Autowired 7private OrderService orderService; 8 9@Autowired 10private BuyerService buyerService; 11 12//创建订单 13@PostMapping("/create") 14public ResultVO create(@Valid OrderForm orderForm, 15BindingResult bindingResult){ 16if (bindingResult.hasErrors()){ 17log.error("[创建订单] 参数不正确,orderForm={}",orderForm); 18throw new SellException(ResultEnum.PARAM_ERROR.getCode(), 19bindingResult.getFieldError().getDefaultMessage()); 20} 21OrderDTO orderDTO = OrderForm2OrderDTOConverter.convert(orderForm); 22if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())){ 23log.error("[创建订单] 购物不能为空"); 24throw new SellException(ResultEnum.CART_EMPTY); 25} 26 27OrderDTO createResult = orderService.create(orderDTO); 28Map map = new HashMap<>(); 29map.put("orderId",createResult.getOrderId()); 30 31return ResultVOUtil.success(map); 32 33} 34//订单列表 35@GetMapping("/list") 36public ResultVO> list(@RequestParam("openid") String openid, 37@RequestParam(value = "https://www.it610.com/article/page",defaultValue = "https://www.it610.com/article/0") Integer page, 38@RequestParam(value = "https://www.it610.com/article/size",defaultValue = "https://www.it610.com/article/10") Integer size){ 39if (StringUtils.isEmpty(openid)){ 40log.error("[查询订单列表] openid为空"); 41throw new SellException(ResultEnum.PARAM_ERROR); 42} 43PageRequest request = new PageRequest(page, size); 44Page orderDTOPage = orderService.findList(openid, request); 45 46return ResultVOUtil.success(orderDTOPage.getContent()); 47} 48 49//订单详情 50@GetMapping("/detail") 51public ResultVO detail(@RequestParam("openid") String openid, 52@RequestParam("orderId") String orderId){ 53 54OrderDTO orderDTO = buyerService.findOrderOne(openid, orderId); 55return ResultVOUtil.success(orderDTO); 56} 57 58//取消订单 59@PostMapping("/cancel") 60public ResultVO cancel(@RequestParam("openid") String openid, 61@RequestParam("orderId") String orderId) { 62 63buyerService.cancelOrderOne(openid, orderId); 64return ResultVOUtil.success(); 65} 66 }

Spring Boot统一异常处理方案示例
文章图片

② service处理返回的结果的异常,抛出自定义异常,由handler捕获返回给页面。
Spring Boot统一异常处理方案示例
文章图片

1 @Service 2 @Slf4j 3 public class BuyerServiceImpl implements BuyerService { 4 5@Autowired 6private OrderService orderService; 7 8@Override 9public OrderDTO findOrderOne(String openid, String orderId) { 10return checkOrderOwner(openid, orderId); 11} 12 13@Override 14public OrderDTO cancelOrderOne(String openid, String orderId) { 15OrderDTO orderDTO = checkOrderOwner(openid, orderId); 16if (orderDTO == null){ 17log.error("[取消订单] 查不到该订单,orderDTO={}",orderId); 18throw new SellException(ResultEnum.ORDER_NOT_EXIST); 19} 20return orderService.cancel(orderDTO); 21} 22 23private OrderDTO checkOrderOwner(String openid, String orderId) { 24OrderDTO orderDTO = orderService.findOne(orderId); 25if (orderDTO == null){ 26return null; 27} 28if (!orderDTO.getBuyerOpenid().equalsIgnoreCase(openid)){ 29log.error("[查询订单] 订单的openid不一致,openid={},orderDTO={}",openid,orderDTO); 30throw new SellException(ResultEnum.ORDER_OWNER_ERROR); 31} 32return orderDTO; 33} 34 35 }

    推荐阅读