需求源自于任何一个业务的编写总会有各种各样的条件判断,需要时时手动抛出异常,又希望让接口返回友好的错误信息。
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(int code) { 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; } }
最后的控制层代码以最简洁的方式调用即可:
@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
原文:https://www.cnblogs.com/fengyumeng/p/9249220.html