定義統一異常類:BusinessException.java
package com.miaoying; import lombok.Data; @Data public class BusinessException extends RuntimeException { /** * 錯誤碼 */ private Integer code; /** * 錯誤信息 */ private String message; public BusinessException(Integer code, String message) { super(message); this.code = code; this.message = message; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BusinessException that = (BusinessException) o; if (!code.equals(that.code)) return false; return message.equals(that.message); } @Override public int hashCode() { int result = code != null ? code.hashCode() : 0; result = 31 * result + (message != null ? message.hashCode() : 0); return result; } }
定義統一的數據返回的結構:ResultResponse<T>.java
package com.miaoying; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @AllArgsConstructor @NoArgsConstructor public class ResultResponse<T> implements Serializable { private static final long serialVersionUID = 5261844042861308860L; private int retCode; private String retMsg; private T rsp; public static <T> ResultResponse<T> wrapSuccessfulResult(T data) { ResultResponse<T> result = new ResultResponse<T>(); result.rsp = data; result.retCode = 200; result.retMsg = "ok"; return result; } }
定義異常攔截器:BusinessExceptionFilter.java
package com.miaoying import com.miaoying.BusinessException; import com.miaoying.ResultResponse; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; @ControllerAdvice @Slf4j public class BusinessExceptionFilter { @ExceptionHandler(BusinessException.class) @ResponseBody public Object handleBusinessException(HttpServletRequest request, BusinessException ex) { log.error("BusinessException code:{},msg:{}", ex.getCode(), ex.getMessage()); ResultResponse response = new ResultResponse(ex.getCode(), ex.getMessage(), null); return JSONObject.toJSON(response); } @ExceptionHandler(Exception.class) @ResponseBody public Object handleException(HttpServletRequest request, Exception ex) { log.error("Exception code:{},msg:{}", 500, ex.getMessage()); ResultResponse response = new ResultResponse(500, "目前業務繁忙,請您稍后!", null); return JSONObject.toJSON(response); } }
在需要自定義異常的地方可以直接以如下形式拋出:
throw new BusinessException(503, "異常測試");
可以將錯誤碼、錯誤信息統一管理成常量,總之,還有優化的空間~
使用上述方式,對filter里拋出的異常捕獲不到,所以需要額外處理,如下所示:
@Component @Slf4j public class RequestFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { String path = ((HttpServletRequest) servletRequest).getRequestURI(); if (path.contains("/exception")) { throw new BusinessException(401, "filter內部拋出異常"); } filterChain.doFilter(servletRequest, servletResponse); } }
如上代碼所示的filter里面拋出異常,是不會轉換為BusinessException的,而是直接拋出:
所以我采取了一個比較low的方式:直接向頁面response出文字內容(據說可以采用Order改變類的執行順序,進行異常捕獲,但我還沒嘗試過):
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { String path = ((HttpServletRequest) servletRequest).getRequestURI(); try { if (path.contains("/exception")) { throw new BusinessException(401, "filter內部拋出異常"); } filterChain.doFilter(servletRequest, servletResponse); return; } catch (Exception e) { log.error(e.getMessage()); ResultResponse response = new ResultResponse(); if (e instanceof BusinessException) { BusinessException be = (BusinessException) e; response.setRetCode(be.getCode()); response.setRetMsg(be.getMessage()); } else { response.setRetCode(500); response.setRetMsg(e.getMessage()); } servletResponse.setCharacterEncoding("utf-8"); servletResponse.getWriter().print(JSONObject.toJSON(response)); return; } }