SpringMVC Controllrt 層的異常處理 :
一、統一的返回格式
當我向前端返回數據時,無論是否成功,我都希望能提供一個統一的返回格式,和一個友善的錯誤提示。所以在完成異常處理前,先提供一個統一的返回格式CommonReturnType,它暫時含有兩個字段
status 表示上傳數據成功或者失敗,data 則是要 上傳的數據。當成功上傳數據時,status 為 “success ”,data 為 數據;當失敗時 status 為 “fail”, data 為 錯誤的詳細。
private String status; private Object data;
代碼:
package com.snapshot2.demo.response; /** * 通用的返回體,用於向前端返回一個通用的數據結構體 */ public class CommonReturnType { //表明返回的類型是"success " 或者 "fail" private String status; //若status = success data內放回前端需要的數據 //若status = fail data內返回相應的錯誤信息 private Object data; /* 兩種創建方法 */ /** * 當只傳入數據data 時,默認成功 * @param result * @return */ public static CommonReturnType creat(Object result){ return creat(result,"success"); } /** * 當傳入status 和 object 時使用這個創建方法 * @param result * @param status * @return */ public static CommonReturnType creat(Object result, String status){ CommonReturnType commonReturnType = new CommonReturnType(); commonReturnType.setData(result); commonReturnType.setStatus(status); return commonReturnType; } /* 省略 Getter and Setter */
二、使用裝飾器模式來自定義一個Controller 層的異常
我們使用一個枚舉來定義自己的一些異常類型,然后使用裝飾器模式來實現對應的功能:
UML 類設計圖:
代碼實現:
CommonErr:
package com.snapshot2.demo.error; /** * 通用的異常接口,整合后端異常反饋給前端,使用裝飾器模式 * 這是裝飾器的統一接口 */ public interface CommonError { public int getErrCode(); public String getErrMsg(); public CommonError setErrMsg(String errMsg); }
CommonErrEnum:
package com.snapshot2.demo.error; public enum CommonErrEnum implements CommonError { //00001 通用的參數不合法錯誤碼 PARAMTER_VALIDATION_ERROR(00001,"參數不合法"), UNKOWN_ERROR(00002,"未知錯誤"), //10000開頭的錯誤碼代表用戶信息相關的錯誤 USER_NOT_EXIST(100001,"用戶不存在"); private int errCode; private String errMsg; /* Constructor */ CommonErrEnum(int errCode, String errMsg) { this.errCode = errCode; this.errMsg = errMsg; } @Override public int getErrCode() { return this.errCode; } @Override public String getErrMsg() { return this.errMsg; } @Override public CommonError setErrMsg(String errMsg) { this.errMsg = errMsg; return this; } }
UserExceprion
package com.snapshot2.demo.error; /** * 使用到了包裝器模式 */ public class UserException extends Exception implements CommonError { //強關聯一個CommonError(CommonErrorEnum) private CommonError commonError; //直接接受一個CommonEnum,用於構造一個業務異常 public UserException(CommonError commonError){ //調用Exception的初始化機制 super(); this.commonError = commonError; } /* Constructor */ public UserException(CommonError commonError,String errMsg){ super(); this.commonError = commonError; this.commonError.setErrMsg(errMsg); } public void setCommonError(CommonError commonError) { this.commonError = commonError; } @Override public int getErrCode() { return this.commonError.getErrCode(); } @Override public String getErrMsg() { return this.commonError.getErrMsg(); } @Override public CommonError setErrMsg(String errMsg) { this.commonError.setErrMsg(errMsg); return this.commonError; } }
我們可以看到,UserException 繼承與Exception類,又實現了CommonErr接口。它關聯了一個實現CommonErr接口的類(這里就是我們定義的Enum類),並且可以使用並增強它的方法。
之后我們就可以在Controller層使用@ExceptionHandler(Exception.class) 注解來捕獲在Controler層出現的Exception異常,並且消化它,向前端返回友善的錯誤提示:
//定義ExceptionHandler解決Controller層未被處理掉的異常 @ExceptionHandler(Exception.class) //Controller 層返回的異常應該屬於后端的異常 @ResponseStatus(HttpStatus.OK) @ResponseBody public Object handlerException(HttpServletRequest request, Exception e){ Map<String,Object> responseData = new HashMap<>(); CommonReturnType commonReturnType = new CommonReturnType(); if(e instanceof UserException){ //強制轉化捕獲的錯誤為UserException UserException userException = (UserException)e; //將錯誤信息轉化為通用的上傳格式 commonReturnType.setStatus("fail"); //將自定義的Exception 信息提取出來放在返回體中 responseData.put("errCode",userException.getErrCode()); responseData.put("errMsg",userException.getErrMsg()); commonReturnType.setData(responseData); } else{ responseData.put("errCode",CommonErrEnum.UNKOWN_ERROR.getErrCode()); responseData.put("errMsg",CommonErrEnum.UNKOWN_ERROR.getErrMsg()); commonReturnType.setStatus("fail"); commonReturnType.setData(responseData); } return commonReturnType; }