統一返回物件和異常處理(二)

席潤發表於2019-02-12
統一返回物件型別
package com.miaosha.response;

public class CommonReturnType {
    //表明對應請求的返回處理結果"success"或"fail"
    private String status;
    //若status=success,則data內為前端需要的json資料
    //若status=fail,則data使用通用的錯誤碼格式
    private Object data;

    //定義一個通用的建立方法
    //返回正確資訊
    public static CommonReturnType create(Object result){
        return CommonReturnType.create(result,"success");
    }

    //返回錯誤資訊,這裡的result為通用錯誤資訊
    public static CommonReturnType create(Object result,String status){
        CommonReturnType type = new CommonReturnType();
        type.setStatus(status);
        type.setData(result);
        return  type;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}
複製程式碼

使用例:

return CommonReturnType.create(itemVO);//成功,有返回資訊
複製程式碼
return CommonReturnType.create(null);//成功,無返回資訊
複製程式碼
return CommonReturnType.create(responseData,"fail");//失敗,返回錯誤資訊
複製程式碼
統一返回錯誤資訊

包裝器業務異常類實現:BusinessException和EmBusinessError共同繼承CommonError,以至於外部不僅可以通過new EmBusinessError或new BusinessException都可以有errCode、errMsg對應的組裝定義,並且共同實現了一個setErrMsg方法,可以用於將原本EmBusinessError中定義的errMsg給覆蓋掉。

上程式碼:

package com.miaosha.error;

public interface CommonError {
    public int getErrCode();
    public String getErrMsg();
    public CommonError serErrMsg(String errMsg);
}
複製程式碼
package com.miaosha.error;

public enum EmBusinessError implements CommonError {
    //通用錯誤型別10001
    PARAMETER_VALIDATION_ERROR(10001,"引數不合法"),
    UNKNOW_ERROR(10002,"未知錯誤"),

    //20000開頭為使用者資訊相關錯誤定義
    USER_NOT_EXIST(20001,"使用者不存在"),
    USER_LOGIN_FAIL(20002,"使用者手機號或密碼不正確"),
    USER_NOT_LOGIN(20003,"使用者還未登入"),

    //30000開頭為交易資訊錯誤定義
    STOCK_NOT_ENOUGH(30001,"庫存不足"),
    ;

    //建構函式
    private EmBusinessError(int errCode,String errMsg){
        this.errCode = errCode;
        this.errMsg = errMsg;
    }

    private int errCode;
    private String errMsg;

    @Override
    public int getErrCode() {
        return this.errCode;
    }

    @Override
    public String getErrMsg() {
        return this.errMsg;
    }

    @Override
    public CommonError serErrMsg(String errMsg) {
        this.errMsg = errMsg;
        return this;
    }
}
複製程式碼
package com.miaosha.error;

//包裝器業務異常類實現
public class BusinessException extends Exception implements CommonError {

    private CommonError commonError;

    //直接接受EmBusinessError的傳參用於構造業務異常
    public BusinessException(CommonError commonError){
        super();
        this.commonError = commonError;
    }

    //接受自定義errMsg的方式構造業務異常
    public BusinessException(CommonError commonError,String errMsg){
        super();
        this.commonError = commonError;
        this.commonError.serErrMsg(errMsg);
    }

    @Override
    public int getErrCode() {
        return this.commonError.getErrCode();
    }

    @Override
    public String getErrMsg() {
        return this.commonError.getErrMsg();
    }

    @Override
    public CommonError serErrMsg(String errMsg) {//用來更改通用錯誤型別的錯誤資訊
        this.commonError.serErrMsg(errMsg);
        return this;
    }
}
複製程式碼

使用使用者註冊服務實現為例:

	@Override
    @Transactional
    public void register(UserModel userModel) throws BusinessException {
        if (userModel==null){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        ValidationResult result = validator.validate(userModel);
        if (result.isHasErrors()){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,result.getErrMsg());
        }
複製程式碼

目前new出來的BusinessException直接被拋到Tomcat的容器層,Tomcat的容器層對應處理這樣一個異常的方式為返回500的錯誤頁。

有沒有一種機制可以攔截掉對應Tomcat的異常處理的方式,然後去解決掉對應的問題?

這裡使用Spring Boot自帶的一個Spring MVC的handlerException去解決這個問題。

異常處理

定義exceptionhandler解決未被controller層吸收的exception(為業務邏輯處理上的問題或業務邏輯錯誤而並非服務端不能處理的錯誤)

package com.miaosha.controller;

import com.miaosha.error.BusinessException;
import com.miaosha.error.EmBusinessError;
import com.miaosha.response.CommonReturnType;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

public class BaseController {
    //定義exceptionhandler解決未被controller層吸收的exception(為業務邏輯處理上的問題或業務邏輯錯誤而並非服務端不能處理的錯誤)
    @ExceptionHandler(Exception.class)//需要指明收到什麼樣的exception之後才會進入它的處理環節,此處定義為根類
    @ResponseStatus(HttpStatus.OK)//捕獲到controller丟擲的exception,並返回HttpStatus.OK,即status=200
    @ResponseBody //handler exception使用這種方式(Object會尋找本地頁面檔案)僅僅只能返回頁面路徑,無法處理viewobject類對應的@ResponseBody形式,加上@ResponseBody註解即可解決
    public Object handlerException(HttpServletRequest request, Exception ex){
        Map<String,Object> responseData = new HashMap<>();
        if (ex instanceof BusinessException){
            BusinessException businessException = (BusinessException)ex;
            responseData.put("errCode",businessException.getErrCode());
            responseData.put("errMsg",businessException.getErrMsg());
        }else {
            responseData.put("errCode", EmBusinessError.UNKNOW_ERROR.getErrCode());
            responseData.put("errMsg",EmBusinessError.UNKNOW_ERROR.getErrMsg());
        }
        return CommonReturnType.create(responseData,"fail");
    }
}
複製程式碼

其作為所有Controller的公用邏輯,所以所有Controller都要繼承它。

參考:

慕課課程《SpringBoot構建電商基礎秒殺專案》

推薦剛入手SpringBoot的同學觀看,老師基礎講的特別好

相關文章