本示例以“前後端分離模式”進行演示,調試用的異常信息通過日誌的形式列印出來,代碼並不完整,僅從異常處理進行部分代碼示例。 ...
一、異常處理的原則
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 }