定义统一异常类: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; } }