Spring Boot統一異常處理方案示例

1、異常處理的原則前端

一、調用方法的時候返回布爾值來代替返回null,這樣能夠 NullPointerException。因爲空指針是java異常裏最噁心的異常。java

二、 catch塊裏別不寫代碼。空catch塊是異常處理裏的錯誤事件,由於它只是捕獲了異常,卻沒有任何處理或者提示。一般你起碼要打印出異常信息,固然你最好根據需求對異常信息進行處理。數據庫

三、能拋受控異常(checked Exception)就儘可能不拋受非控異常(unchecked Exception[Error或者RuntimeException的異常])。經過去掉重複的異常處理代碼,能夠提升代碼的可讀性。後端

四、 絕對不要讓你的數據庫相關異常顯示到客戶端。因爲絕大多數數據庫和SQLException異常都是受控異常,在Java中,你應該在DAO層把異常信息處理,而後返回處理過的能讓用戶看懂並根據異常提示信息改正操做的異常信息。app

五、 在Java中,必定要在數據庫鏈接,數據庫查詢,流處理後,在finally塊中調用close()方法。前後端分離

2、示例說明ide

本示例以「先後端分離模式」進行演示,調試用的異常信息經過日誌的形式打印出來,代碼並不完整,僅從異常處理進行部分代碼示例。this

一、建立異常類spa

 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 }

二、使用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 }

三、異常的信息經過枚舉統必定義,方便定義管理

 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 }

四、使用異常類

① 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 }
相關文章
相關標籤/搜索