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、創建異常類

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

2、使用Handler類捕獲異常,統一格式返回給前端

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

  統一格式類:

 1 public class ResultVOUtil {
 2 
 3     public static ResultVO success(Object object) {
 4         ResultVO resultVO = new ResultVO();
 5         resultVO.setData(object);
 6         resultVO.setCode(0);
 7         resultVO.setMsg("成功");
 8         return resultVO;
 9     }
10 
11     public static ResultVO success() {
12         return success(null);
13     }
14 
15     public static ResultVO error(Integer code,String msg) {
16         ResultVO resultVO = new ResultVO(); 17  resultVO.setCode(code); 18  resultVO.setMsg(msg); 19         return resultVO; 20     }
21 
22 }
 1 @Data
 2 public class ResultVO<T> implements Serializable{
 3 
 4     private static final long serialVersionUID = 8960474786737581150L;
 5 
 6     /**
 7      * 錯誤碼
 8      */
 9     private Integer code;
10     /**
11      *提示信息
12      */
13     private String msg;
14     /**
15      * 具體內容
16      */
17     private T data;
18 
19 }

3、異常的信息通過枚舉統一定義,方便定義管理

 1 @Getter
 2 public enum ResultEnum {
 3 
 4     SUCCESS(0,"成功"),
 5 
 6     PARAM_ERROR(1,"參數不正確"),
 7 
 8     PRODUCT_NOT_EXIST(10,"商品不存在"),
 9 
10     PRODUCT_STOCK_ERROR(11,"商品庫存不正確"),
11 
12     ORDER_NOT_EXIST(12,"訂單不存在"),
13 
14     ORDERDETAIL_NOT_EXIST(13,"訂單詳情不存在"),
15 
16     ORDER_STATUS_ERROR(14,"訂單狀態不正確"),
17 
18     ORDER_UPDATE_FAIL(15,"訂單更新失敗"),
19 
20     ORDER_DETAIL_EMPTY(16,"訂單詳情為空"),
21 
22     CART_EMPTY(18,"購物車為空"),
23 
24     ORDER_OWNER_ERROR(19,"該訂單不屬於當前用戶"),
25     ;
26 
27     private Integer code;
28     private String message;
29 
30     ResultEnum(Integer code, String message) {
31         this.code = code;
32         this.message = message;
33     }
34 
35 }

4、使用異常類

① controller層處理頁面傳來參數的校驗,如參數不正確,拋出自定義異常,由handler捕獲返回給頁面。

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

② service處理返回的結果的異常,拋出自定義異常,由handler捕獲返回給頁面。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM