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>

        斷言+異常處理類(lèi),代碼更簡(jiǎn)潔了

        共 25562字,需瀏覽 52分鐘

         ·

        2022-07-04 18:31

        點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)??

        文章來(lái)源:https://c1n.cn/E6fZj


        目錄
        • 背景

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

        • 附上代碼


        背景


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


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


        假如我們?cè)诿總€(gè)接口中都去包裝異常信息進(jìn)行返回就會(huì)讓代碼變得很冗余且混亂。在我司的實(shí)際項(xiàng)目開(kāi)發(fā)過(guò)程中,我們會(huì)巧用斷言去簡(jiǎn)化代碼。


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


        假設(shè)我們定義的標(biāo)準(zhǔn)接口響應(yīng)實(shí)體為 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è)務(wù)邏輯時(shí)代碼就會(huì)變成這樣,看起來(lái)非常多代碼:
         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("查無(wú)此服務(wù)單");
                 return result;
             }
             if(serviceOrder.getOrderStatus().equals(cancelOrderStatus)){
                 result.setSuccess(false);
                 result.setResponseCode(ErrorCodeEnum.FAIL.getCode());
                 result.setResponseMsg("已取消的服務(wù)單不允許再次取消");
                 return result;
             }
             if(serviceOrder.getSortOrderId() != null){
                 result.setSuccess(false);
                 result.setResponseCode(ErrorCodeEnum.FAIL.getCode());
                 result.setResponseMsg("已配置物料的服務(wù)單不允許取消");
                 return result;
             }
             // ...other check
         
             // ...do something
             return result;
         }


        然后在上面這個(gè)代碼基礎(chǔ)上,我們可以觀察到,里面其實(shí)有非常多的重復(fù)代碼,完全可以把它們裝到 ApiResult 里面。


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


        在原 ApiResult 實(shí)體中增加一些公用的處理方法:
         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è)務(wù)邏輯處理就變成這樣了,看起來(lái)還不錯(cuò)是不是:
         /**
          * 取消服務(wù)單(不用斷言)
          */

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


        但是我們可以用異常處理類(lèi)+斷言處理得更加簡(jiǎn)化。


        增加異常處理類(lèi):
         @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());
             }
         }


        增加異常類(lèi) BusinessException:
         /**
          * 業(yè)務(wù)異常,異常信息會(huì)返回到前端展示給用戶
          *
          * @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;
             }
         }


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

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

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

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

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


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

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


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


        附上代碼


        統(tǒng)一異常處理類(lèi):
         /**
          * 統(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(), "登錄已失效,請(qǐng)重新登錄!");
             }
         
             @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"網(wǎng)絡(luò)異常,請(qǐng)稍后再試"),
         
             SUCCESS(0"請(qǐng)求成功"),
         
             MAX_UPLOAD_SIZE_ERROR(1000"上傳文件不能超過(guò)20M"),
         
             SERVICE_BUSY_ERROR(1000"服務(wù)器正在繁忙,請(qǐng)稍后再試哦~"),
         
             REQUEST_PARAMS_FAIL(1001"參數(shù)錯(cuò)誤"),
         
             USER_NOT_LOGIN(1002"用戶未登錄,請(qǐng)重新登錄"),
         
             USER_HAS_EXIST_LOGIN(1007"用戶已經(jīng)存在,請(qǐng)檢查!"),
         
             USER_CODE_NOT_EXIST(1008"用戶編碼不存在,請(qǐng)檢查!"),
         
             REQUEST_PARAMS_FORMAT_ERROR(1102"請(qǐng)求參數(shù)格式異常"),
         
             PASSWORD_SAFETY_ERROE(2204"密碼不符合安全規(guī)則,請(qǐng)通過(guò)忘記密碼重新設(shè)置8-18位數(shù)字+字母組合密碼"),
         
             TOKEN_EXPIRED(2301"token過(guò)期"),
         
             TOKEN_ERROR(2302"token驗(yàn)證失敗"),
         
             INTERFACE_ERROR(10000"接口服務(wù)器異常");
         
             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;
             }
         }

        1. 高頻面試題 | Redis 如何實(shí)現(xiàn)庫(kù)存扣減操作?

        2. JVM 內(nèi)存布局詳解,圖文并茂,寫(xiě)得太好了!

        3. 重磅:國(guó)產(chǎn)IDE發(fā)布,由阿里研發(fā),完全開(kāi)源?。ǜ咝阅?高定制性)

        4. SpringBoot+Nacos+Kafka簡(jiǎn)單實(shí)現(xiàn)微服務(wù)流編排

        最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

        獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

        PS:因公眾號(hào)平臺(tái)更改了推送規(guī)則,如果不想錯(cuò)過(guò)內(nèi)容,記得讀完點(diǎn)一下在看,加個(gè)星標(biāo),這樣每次新文章推送才會(huì)第一時(shí)間出現(xiàn)在你的訂閱列表里。

        點(diǎn)“在看”支持小哈呀,謝謝啦??

        瀏覽 29
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        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>
            国产伦精品一区二区三区视频1 | 成人做爱视频免费线上免费播放 | 麻豆十八禁 | 日韩精品成人一区二区在线 | 激情丁香婷 | 国产精品久久久久久一二三四五 | 韩国免费毛片 | 二攻一受3p寝室高h | 17c.白丝喷水 自慰 | 男女啪啪的网站 |