spring boot 統一異常處理
阿新 • • 發佈:2018-07-01
res status fin erro throwable instance 拋出異常 方案 let
需求源自於任何一個業務的編寫總會有各種各樣的條件判斷,需要時時手動拋出異常,又希望讓接口返回友好的錯誤信息。
spring boot提供的幫助是自動將異常重定向到路由為/error的控制器
但是我們又希望手動拋出的異常與正常的數據返回為同一類型
所以我的解決方案由三個步驟組成:
1.一個異常枚舉類 StatusCodeEnum.java
public enum StatusCodeEnum implements Serializable { SUCCESS(0, "成功"), ERROR(-1, "失敗"), USER_INVALID(60000, "無效用戶"), SYS_ARG_INVALID(11000, "無效參數"), ; private static final long serialVersionUID = 1L; private int code; private String msg; StatusCodeEnum(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public void setCode(intcode) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } //根據code獲取對應枚舉 public static StatusCodeEnum getByCode(int code) { StatusCodeEnum[] values = StatusCodeEnum.values();for (StatusCodeEnum bizStatusCodeEnum : values) { if (bizStatusCodeEnum.code == code) { return bizStatusCodeEnum; } } return null; } }
2.一個異常調用類 BaseException.java
因為拋出異常只能拋出字符串 所以這裏使用了com.alibaba.fastjson.JSON包
public class BaseException { private int code; private String message; public static void error(StatusCodeEnum statusCodeEnum) throws Exception { error(statusCodeEnum.getCode(),statusCodeEnum.getMsg()); } public static void error(String message) throws Exception { error(-1,message); } public static void error(int code,String message) throws Exception { BaseException baseException = new BaseException(); baseException.setCode(code); baseException.setMessage(message); throw new Exception(JSON.toJSONString(baseException)) ; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } @Override public String toString() { return "BaseException{" + "code=" + code + ", message=‘" + message + ‘\‘‘ + ‘}‘; } }
3.異常處理控制器 ErrorController.java
@Controller public class ErrorController extends AbstractErrorController{ @Autowired ObjectMapper objectMapper; public ErrorController() { super(new DefaultErrorAttributes()); } @Override public String getErrorPath() { return null; } @RequestMapping("/error") @ResponseBody public BaseRs getErrorPath(HttpServletRequest request, HttpServletResponse response) { Map<String,Object> model = Collections.unmodifiableMap(getErrorAttributes(request,false)); //獲取異常 可將異常打印到日誌 Throwable cause = getCause(request); int status = (Integer)model.get("status"); //自定義友好錯誤信息 String msg = (String)model.get("message"); JSONObject object = JSONObject.parseObject(msg); int code = object.getInteger("code"); String message = object.getString("message"); return new BaseRs(code,message); } protected Throwable getCause(HttpServletRequest request) { Throwable error = (Throwable)request.getAttribute("javax.servlet.error.exception"); if(null == error){ //MVC有可能會封裝異常成ServletException ,需要調用getCause獲取真正的異常 while (error instanceof ServletException && error.getCause() != null){ error = ((ServletException) error).getCause(); } } return error; } }
以上三個文件為異常處理的核心
其中的BaseRs類是統一數據返回
public class BaseRs<T> implements Serializable { private int code; private String message; public BaseRs() { } /** * 返回內容 */ private T content; public int getCode() { return code; } public String getMessage() { return message; } public T getContent() { return content; } public BaseRs(int code, String message) { this.code = code; this.message = message; } public BaseRs(int code, String message, T content) { this.code = code; this.message = message; this.content = content; } public BaseRs(StatusCodeEnum status) { this.code = status.getCode(); this.message = status.getMsg(); } public BaseRs(StatusCodeEnum status, T content) { this.code = status.getCode(); this.message = status.getMsg(); this.content = content; } public static <V> BaseRs ok(V content) { return new BaseRs(StatusCodeEnum.SUCCESS, content); } public static BaseRs ok() { return new BaseRs(StatusCodeEnum.SUCCESS); } public static BaseRs error(StatusCodeEnum error) { return new BaseRs(error); } public void setCode(StatusCodeEnum status) { this.code = status.getCode(); } public void setMessage(String message) { this.message = message; } public void setContent(T content) { this.content = content; } @Override public String toString() { return "BaseRs{" + "code=" + code + ", message=‘" + message + ‘\‘‘ + ", content=" + content + ‘}‘; } public void setCode(int code) { this.code = code; } }View Code
最後的控制層代碼以最簡潔的方式調用即可:
@Controller public class IndexController { @RequestMapping("/a") @ResponseBody public BaseRs a() throws Exception{ boolean s = false; if(!s){ BaseException.error(StatusCodeEnum.USER_INVALID); } return new BaseRs(StatusCodeEnum.SUCCESS); } }
本篇博客的碼雲地址: https://gitee.com/zhao-baolin/springboot_error
spring boot 統一異常處理