1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        斷言+異常處理類,代碼更簡潔了

        共 25420字,需瀏覽 51分鐘

         ·

        2022-08-01 18:59

        今日推薦
        為什么很多 SpringBoot 開發(fā)者放棄了 Tomcat,選擇了 Undertow?
        專業(yè)的 Redis 可視化管理工具,支持跨平臺,UI美呆了!
        利用Java8新特征,重構傳統(tǒng)設計模式,你學會了嗎?
        接口請求合并的3種技巧,性能直接爆表!
        史上最全的 IDEA Debug 調試技巧(超詳細案例)
        利用多線程批量拆分 List 導入數(shù)據(jù)庫,效率杠杠的

        文章來源:https://c1n.cn/E6fZj


        目錄
        • 背景

        • 業(yè)務異常處理示例

        • 附上代碼


        背景


        軟件開發(fā)過程中,不可避免的是需要處理各種異常,所以代碼中就會出現(xiàn)大量的 try {...} catch {...} finally {...} 代碼塊,不僅有大量的冗余代碼,而且還影響代碼的可讀性。


        另一個就是面對業(yè)務異常的情況,我們經常需要將業(yè)務異常結果組裝成統(tǒng)一的信息返回給前端進行提示。


        假如我們在每個接口中都去包裝異常信息進行返回就會讓代碼變得很冗余且混亂。在我司的實際項目開發(fā)過程中,我們會巧用斷言去簡化代碼。


        業(yè)務異常處理示例


        假設我們定義的標準接口響應實體為 ApiResult:
         @Data
         @Builder
         @NoArgsConstructor
         @AllArgsConstructor
         public class ApiResult<Timplements Serializable {
             private static final long serialVersionUID = 411731814484355577L;
             private int responseCode;
             private String responseMsg;
             private boolean isSuccess;
             private T data;
         
             public String toString() {
                 return "ApiResult(responseCode=" + this.getResponseCode() + ", responseMsg=" + this.getResponseMsg() + ", isSuccess=" + this.isSuccess() + ", data=" + this.getData() + ")";
             }
         }


        那么我們接口處理業(yè)務邏輯時代碼就會變成這樣,看起來非常多代碼:
         public ApiResult cancelService(@PathVariable Long serviceOrderId){
             ServiceOrder serviceOrder = serviceOrderMapper.selectByPrimaryKey(serviceOrderId);
             ApiResult result = new ApiResult<>();
             if (ObjectUtil.isNull(serviceOrder)) {
                 result.setSuccess(false);
                 result.setResponseCode(ErrorCodeEnum.FAIL.getCode());
                 result.setResponseMsg("查無此服務單");
                 return result;
             }
             if(serviceOrder.getOrderStatus().equals(cancelOrderStatus)){
                 result.setSuccess(false);
                 result.setResponseCode(ErrorCodeEnum.FAIL.getCode());
                 result.setResponseMsg("已取消的服務單不允許再次取消");
                 return result;
             }
             if(serviceOrder.getSortOrderId() != null){
                 result.setSuccess(false);
                 result.setResponseCode(ErrorCodeEnum.FAIL.getCode());
                 result.setResponseMsg("已配置物料的服務單不允許取消");
                 return result;
             }
             // ...other check
         
             // ...do something
             return result;
         }


        然后在上面這個代碼基礎上,我們可以觀察到,里面其實有非常多的重復代碼,完全可以把它們裝到 ApiResult 里面。


        這也是我看到很多開源框架的處理方式(PS:所以我第一個自己寫的框架也是這么處理的)


        在原 ApiResult 實體中增加一些公用的處理方法:
         public static ApiResult<String> success() {
             return success("success");
         }
         
         public static <T> ApiResult<T> success(T data{
             return (new ApiResult()).setResponseCode(0).setResponseMsg("操作成功").setSuccess(true).setData(data);
         }
         
         public static ApiResult<String> fail() {
             return fail(-1);
         }
         
         public static ApiResult<String> fail(int code{
             return fail(code, "fail");
         }
         
         public static <T> ApiResult<T> fail(T data{
             return fail(-1, data);
         }
         
         public static <T> ApiResult<T> fail(int code, T data{
             return (new ApiResult()).setResponseCode(code).setResponseMsg("操作失敗").setSuccess(false).setData(data);
         }
         
         public static <T> ApiResult<T> success(int code, String message, T data{
             return (new ApiResult()).setResponseCode(code).setResponseMsg(message).setSuccess(true).setData(data);
         }
         
         public static <T> ApiResult<T> fail(int code, String message, T data{
             return (new ApiResult()).setResponseCode(code).setResponseMsg(message).setSuccess(false).setData(data);
         }


        然后業(yè)務邏輯處理就變成這樣了,看起來還不錯是不是:
         /**
          * 取消服務單(不用斷言)
          */

         public ApiResult cancelService(Long serviceOrderId){
             ServiceOrder serviceOrder = serviceOrderMapper.selectByPrimaryKey(serviceOrderId);
             ApiResult result = new ApiResult<>();
             if (ObjectUtil.isNull(serviceOrder)) {
                 result = ApiResult.fail(ErrorCodeEnum.FAIL.getCode(), "查無此服務單");
                 return result;
             }
             if(serviceOrder.getOrderStatus().equals(cancelOrderStatus)){
                 result = ApiResult.fail(ErrorCodeEnum.FAIL.getCode(), "已取消的服務單不允許再次取消");
                 return result;
             }
             if(serviceOrder.getSortOrderId() != null){
                 result = ApiResult.fail(ErrorCodeEnum.FAIL.getCode(), "已配置物料的服務單不允許取消");
                 return result;
             }
             // ...other check
         
             // ...do something
             return result;
         }


        但是我們可以用異常處理類+斷言處理得更加簡化。


        增加異常處理類:
         @Slf4j
         @ControllerAdvice
         public class GlobalExceptionHandler {
             @ExceptionHandler(value = BusinessException.class)
             @ResponseBody
             public ResponseBean businessExceptionHandler(BusinessException e) {
                 log.info("business error : {}",e.getMessage(),e);
                 if (e.getCode() == -1) {
                     return ResponseBean.error(ApiCode.SERVICE_ERROR.getValue(), ApiCode.SERVICE_ERROR.getMessage());
                 }
                 return ResponseBean.error(e.getCode(), e.getMessage());
             }
         }


        增加異常類 BusinessException:
         /**
          * 業(yè)務異常,異常信息會返回到前端展示給用戶
          *
          * @date 2020/12/15 14:18
          */

         public class BusinessException extends RuntimeException {
             private static final long serialVersionUID = -5770538329754222306L;
         
             private int code = 1;
             private Level level;
         
             public BusinessException(int code, String message, Throwable cause) {
                 super(message, cause);
                 this.code = code;
             }
         
             public BusinessException(String message) {
                 super(message);
             }
         
             public BusinessException(Level level, String message) {
                 super(message);
                 this.level = level;
             }
         
             public BusinessException(Throwable cause) {
                 super(cause);
             }
         
             public BusinessException(int code, String message) {
                 super(message);
                 this.code = code;
             }
         
             public int getCode() {
                 return this.code;
             }
         
             public final Level getLevel() {
                 return this.level;
             }
         }


        增加斷言工具類 AssertUtil:
         public class AssertUtil extends cn.com.bluemoon.common.web.exception.AssertUtil  {
             public AssertUtil() {
             }
         
             /**
              * 服務調用異常
              * @param expression
              * @param message
              */

             public static void isTrueServiceInvoke(boolean expression, String message) {
                 if (!expression) {
                     throw new ServiceInvokeException(message);
                 }
             }
         
             /**
              * 拋出異常(默認錯誤1000)
              * @param message
              */

             public static void businessInvalid(String message) {
                 throw new BusinessException(ApiCode.SERVICE_ERROR.getValue(), message);
             }
         
             /**
              * 表達式為真即拋出異常(默認錯誤1000)
              *
              * @param expression
              * @param message
              */

             public static void businessInvalid(boolean expression, String message) {
                 if (expression) {
                     throw new BusinessException(ApiCode.SERVICE_ERROR.getValue(), message);
                 }
             }
         
             /**
              * 表達式為真即拋出異常
              *
              * @param expression
              * @param message
              */

             public static void businessInvalid(boolean expression, int code, String message) {
                 if (expression) {
                     throw new BusinessException(code, message);
                 }
             }
         }


        最后優(yōu)化的結果:
         /**
          * 取消服務單
          */

         public ApiResult cancelService(@PathVariable Long serviceOrderId){
             ServiceOrder serviceOrder = serviceOrderMapper.selectByPrimaryKey(serviceOrderId);
             AssertUtil.businessInvalid(ObjectUtil.isNull(serviceOrder),"查無此服務單");
             AssertUtil.businessInvalid(serviceOrder.getOrderStatus().equals(cancelOrderStatus),"查無此服務單");
             AssertUtil.businessInvalid(serviceOrder.getSortOrderId() != null,"查無此服務單");
             // ...other check
         
             // ...do something
             return ApiResult.success();
         }


        最后,我們可以看到我們的接口由 19 行的業(yè)務檢查代碼簡化到了 3 行。這只是單接口的情況下,在業(yè)務多且復雜的情況下能給我們節(jié)省更多的開發(fā)時間,把精力集中在核心業(yè)務上。


        附上代碼


        統(tǒng)一異常處理類:
         /**
          * 統(tǒng)一異常處理
          */

         @Slf4j
         @ControllerAdvice
         public class GlobalExceptionHandler {
         
             @ExceptionHandler(value = AssertException.class)
             @ResponseBody
             public ResponseBean bootExceptionHandler(AssertException e) {
                 ApiCode apiCode = ApiCode.getObjectByValue(e.getCode());
                 log.error("business error : {}", e.getMessage(), e);
                 if (e.getCode() == -1) {
                     return ResponseBean.error(ApiCode.SERVICE_ERROR.getValue(), ApiCode.SERVICE_ERROR.getMessage());
                 }
                 return ResponseBean.error(apiCode.getValue(), e.getMessage());
             }
         
             @ExceptionHandler(value = com.alibaba.fastjson.JSONException.class)
             public ResponseBean alibabaJsonExceptionHandler(com.alibaba.fastjson.JSONException e) {
                 ResponseBean response = new ResponseBean(false, ApiCode.PARAM_FORMAT_INCORR.getValue(), ApiCode.PARAM_FORMAT_INCORR.getMessage() + e.getMessage(), null);
                 log.error("1102", e);
                 return response;
             }
         
             @ExceptionHandler(value = JSONException.class)
             @ResponseBody
             public ResponseBean jsonExceptionHandler(JSONException e) {
                 ResponseBean response = new ResponseBean(false, ApiCode.PARAM_FORMAT_INCORR.getValue(), ApiCode.PARAM_FORMAT_INCORR.getMessage() + e.getMessage(), null);
                 log.error(ApiCode.PARAM_FORMAT_INCORR.getValue() + "", e);
                 return response;
             }
         
             @ExceptionHandler(value = JsonParseException.class)
             @ResponseBody
             public ResponseBean jsonParseExceptionHandler(JsonParseException e) {
                 ResponseBean response = new ResponseBean(false, ApiCode.PARAM_FORMAT_INCORR.getValue(), String.format(ApiCode.PARAM_FORMAT_INCORR.getMessage() + ":%s", e.getMessage()), null);
                 log.error(ApiCode.PARAM_FORMAT_INCORR.getValue() + "", e);
                 return response;
             }
         
             @ExceptionHandler(value = Exception.class)
             @ResponseBody
             public ResponseBean exceptionHandler(Exception e) {
                 ResponseBean response = new ResponseBean(false, ApiCode.SERVICE_ERROR.getValue(), ApiCode.SERVICE_ERROR.getMessage(), null);
                 log.error(ApiCode.SERVICE_ERROR.getValue() + "", e);
                 return response;
             }
         
             @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
             @ResponseBody
             public ResponseBean exceptionHandle(MethodArgumentTypeMismatchException e) {
                 ResponseBean response = new ResponseBean(false, ApiCode.PARAM_FORMAT_INCORR.getValue(), String.format(ApiCode.PARAM_FORMAT_INCORR.getMessage() + ":%s", e.getMessage()), null);
                 log.error(ApiCode.PARAM_FORMAT_INCORR.getValue() + "", e);
                 return response;
             }
         
             @ExceptionHandler(value = WebException.class)
             @ResponseBody
             public ResponseBean exceptionHandler(WebException e) {
                 ResponseBean response = new ResponseBean(e.getIsSuccess(), e.getResponseCode(), e.getResponseMsg(), null);
                 log.error(e.getResponseCode() + "", e);
                 return response;
             }
         
             @ExceptionHandler(value = IllegalArgumentException.class)
             @ResponseBody
             public ResponseBean exceptionHandler(IllegalArgumentException e) {
                 log.error("illegal request : {}", e.getMessage(), e);
                 return ResponseBean.error(ApiCode.PARAM_INVALID.getValue(), ApiCode.PARAM_INVALID.getMessage());
             }
         
             @ExceptionHandler(value = ServiceInvokeException.class)
             @ResponseBody
             public ResponseBean exceptionHandler(ServiceInvokeException e) {
                 log.error("serviceInvoke error request : {}", e.getMessage(), e);
                 return ResponseBean.error(ApiCode.SERVICE_ERROR.getValue(), ApiCode.SERVICE_ERROR.getMessage());
             }
         
             @ExceptionHandler(value = BusinessException.class)
             @ResponseBody
             public ResponseBean businessExceptionHandler(BusinessException e) {
                 log.info("business error : {}",e.getMessage(),e);
                 if (e.getCode() == -1) {
                     return ResponseBean.error(ApiCode.SERVICE_ERROR.getValue(), ApiCode.SERVICE_ERROR.getMessage());
                 }
                 return ResponseBean.error(e.getCode(), e.getMessage());
             }
         
             @ResponseBody
             @ExceptionHandler(MethodArgumentNotValidException.class)
             public ResponseBean  exceptionHandler(MethodArgumentNotValidException e) {
                 log.info("req params error", e);
                 String message = e.getBindingResult().getFieldError().getDefaultMessage();
                 if (StringUtils.isNotBlank(message) && !"不能為空".equals(message)) {
                     return ResponseBean.error(ApiCode.PARAM_INVALID.getValue(), message);
                 }
                 return ResponseBean.error(ApiCode.PARAM_INVALID.getValue(), ApiCode.PARAM_INVALID.getMessage());
             }
         
             @ExceptionHandler(value = TokenErrorException.class)
             @ResponseBody
             public ResponseBean tokenErrorExceptionHandler(TokenErrorException e) {
                 log.info("登錄失效 : {}",e.getMessage(),e);
                 return ResponseBean.error(ApiCode.SERVICE_ERROR.getValue(), "登錄已失效,請重新登錄!");
             }
         
             @ExceptionHandler(value = ServiceException.class)
             @ResponseBody
             public ResponseBean businessExceptionHandler(ServiceException e) {
                 log.info("service error : {}",e.getMessage(),e);
                 return ResponseBean.error(ApiCode.SERVICE_ERROR.getValue(), e.getMessage());
             }
         }


        異常情況枚舉,僅作參考:
         public enum ErrorCodeEnum implements EnumBase{
         
             FAIL(-1"網絡異常,請稍后再試"),
         
             SUCCESS(0"請求成功"),
         
             MAX_UPLOAD_SIZE_ERROR(1000"上傳文件不能超過20M"),
         
             SERVICE_BUSY_ERROR(1000"服務器正在繁忙,請稍后再試哦~"),
         
             REQUEST_PARAMS_FAIL(1001"參數(shù)錯誤"),
         
             USER_NOT_LOGIN(1002"用戶未登錄,請重新登錄"),
         
             USER_HAS_EXIST_LOGIN(1007"用戶已經存在,請檢查!"),
         
             USER_CODE_NOT_EXIST(1008"用戶編碼不存在,請檢查!"),
         
             REQUEST_PARAMS_FORMAT_ERROR(1102"請求參數(shù)格式異常"),
         
             PASSWORD_SAFETY_ERROE(2204"密碼不符合安全規(guī)則,請通過忘記密碼重新設置8-18位數(shù)字+字母組合密碼"),
         
             TOKEN_EXPIRED(2301"token過期"),
         
             TOKEN_ERROR(2302"token驗證失敗"),
         
             INTERFACE_ERROR(10000"接口服務器異常");
         
             private final int code;
             private final String msg;
         
             ErrorCodeEnum(int code, String msg) {
                 this.code = code;
                 this.msg = msg;
             }
         
             @Override
             public int getCode() {
                 return this.code;
             }
         
             @Override
             public String getMsg() {
                 return this.msg;
             }
         }


        最后,給大家推薦一個我的知識星球,現(xiàn)在加入,前 100 名,只需要 25 元即可,非常優(yōu)惠。
        瀏覽 30
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            大香蕉尹人 | 啊啊好爽好舒服 | 岛国无码精品 | 肏肥屄| 欧美xxxx吸乳 | 色婷婷久久久Ma | 欧美性猛交XXXX乱大交 | 大香蕉性爱网 | 国产精品自拍自视频图片小说 | 免费观看BBB毛片大全 |