springboot中的全局异常
在我们前后端分离项目中往往都会有统一返回结果类,也正是为了在出现错误或者异常时,对前端的返回有个友好的提示,全局对全局异常的捕捉,并直接返回正确的提示信息给前端
这个就不用导入jar了
springboot 自带了一个ControllerAdvice注解 可以对异常信息进行操作
-
首先我们先来创建个pojo
@Data public class User implements Serializable { private static final long serialVersionUID = 1L; /** * 编号 */ private int id; /** * 姓名 */ private String name; /** * 年龄 */ private int age; }
-
再创建一个错误信息映射的枚举
public enum CommonEnum implements BaseErrorInfoInterface { // 数据操作错误定义 SUCCESS("200", "成功!"), BODY_NOT_MATCH("400","请求的数据格式不符!"), SIGNATURE_NOT_MATCH("401","请求的数字签名不匹配!"), NOT_FOUND("404", "未找到该资源!"), INTERNAL_SERVER_ERROR("500", "服务器内部错误!"), SERVER_BUSY("503","服务器正忙,请稍后再试!") ; /** * 错误码 */ private String resultCode; /** * 错误描述 */ private String resultMsg; CommonEnum(String resultCode, String resultMsg) { this.resultCode = resultCode; this.resultMsg = resultMsg; } @Override public String getResultCode() { return null; } @Override public String getResultMsg() { return null; }
-
创建一个baseerror接口来给后面我们所需要的异常处理类调用
public interface BaseErrorInfoInterface { /** * 错误码 * * @return */ String getResultCode(); /** * 错误描述 * * @return */ String getResultMsg(); }
-
我们就声明一个业务异常把,也不搞什么daoException和ServiceException了
@Data public class BizException extends RuntimeException { private static final long serialVersionUID = 1L; /** * 错误码 */ protected String errorCode; /** * 错误信息 */ protected String errorMsg; public BizException() { super(); } public BizException(BaseErrorInfoInterface errorInfoInterface) { super(errorInfoInterface.getResultCode()); this.errorCode = errorInfoInterface.getResultCode(); this.errorMsg = errorInfoInterface.getResultMsg(); } public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) { super(errorInfoInterface.getResultCode(), cause); this.errorCode = errorInfoInterface.getResultCode(); this.errorMsg = errorInfoInterface.getResultMsg(); } public BizException(String errorMsg) { super(errorMsg); this.errorMsg = errorMsg; } public BizException(String errorCode, String errorMsg) { super(errorCode); this.errorCode = errorCode; this.errorMsg = errorMsg; } public BizException(String errorCode, String errorMsg, Throwable cause) { super(errorCode, cause); this.errorCode = errorCode; this.errorMsg = errorMsg; } @Override public String getMessage() { return errorMsg; } @Override public Throwable fillInStackTrace() { return this; } }
-
现在是时候把我们的全局返回类搬出来了,这里我运用到了链式编程,不懂得可以baidu,这里还定义了各种情况的返回
@Accessors(chain = true) @Data public class ReturnResult { /** * 响应代码 */ private String code; /** * 响应消息 */ private String message; /** * 响应结果 */ private Object result; public ReturnResult() { } public ReturnResult(BaseErrorInfoInterface errorInfo) { this.code = errorInfo.getResultCode(); this.message = errorInfo.getResultMsg(); } /** * 成功(但是没数据) * * @return */ public static ReturnResult success() { return success(null); } /** * 成功并且有数据 * * @param data * @return */ public static ReturnResult success(Object data) { return new ReturnResult() .setCode(CommonEnum.SUCCESS.getResultCode()) .setMessage(CommonEnum.SUCCESS.getResultMsg()) .setResult(data); } /** * 失败(不自定义code和msg) */ public static ReturnResult error(BaseErrorInfoInterface errorInfo) { return new ReturnResult() .setCode(errorInfo.getResultCode()) .setMessage(errorInfo.getResultMsg()) .setResult(null); } /** * 失败(自定义code和msg) */ public static ReturnResult error(String code, String message) { return new ReturnResult() .setCode(code) .setMessage(message) .setResult(null); } /** * 失败code:-1 msg自定 */ public static ReturnResult error(String message) { return new ReturnResult() .setCode("-1") .setMessage(message) .setResult(null); } @Override public String toString() { return "JSONObject.toJSONString(this)"; } }
-
现在是我们的主角正式出场了,全局异常处理
@ControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 处理自定义的业务异常 * * @param req * @param e * @return */ @ExceptionHandler(value = BizException.class) @ResponseBody public ReturnResult bizExceptionHandler(HttpServletRequest req, BizException e) { log.error("发生业务异常!原因是:{}", e.getErrorMsg()); return ReturnResult.error(e.getErrorCode(), e.getErrorMsg()); } /** * 处理空指针的异常 * * @param req * @param e * @return */ @ExceptionHandler(value = NullPointerException.class) @ResponseBody public ReturnResult exceptionHandler(HttpServletRequest req, NullPointerException e) { log.error("发生空指针异常!原因是:", e.getMessage()); return ReturnResult.error(CommonEnum.BODY_NOT_MATCH); } /** * 处理其他异常 * * @param req * @param e * @return */ @ExceptionHandler(value = Exception.class) @ResponseBody public ReturnResult exceptionHandler(HttpServletRequest req, Exception e) { log.error("未知异常!原因是:", e.getMessage()); return ReturnResult.error(CommonEnum.INTERNAL_SERVER_ERROR); } }
-
后面就可以写个controller测试了
@RestController public class controller { @PostMapping("/user") public boolean insert(@RequestBody User user) { System.out.println("开始新增..."); //如果姓名为空就手动抛出一个自定义的异常! if (user.getName() == null) { throw new BizException("-1", "用户姓名不能为空!"); } return true; } @PutMapping("/user") public boolean update(@RequestBody User user) { System.out.println("开始更新..."); //这里故意造成一个空指针的异常,并且不进行处理 String str = null; str.equals("111"); return true; } @DeleteMapping("/user") public boolean delete(@RequestBody User user) { System.out.println("开始删除..."); //这里故意造成一个异常,并且不进行处理 Integer.parseInt("abc123"); return true; } @GetMapping("/user") public List<User> findByUser(User user) { System.out.println("开始查询..."); List<User> userList = new ArrayList<>(); User user2 = new User(); user2.setId(1); user2.setName("xuwujing"); user2.setAge(18); userList.add(user2); return userList; } }
讲了这么多,也实现了,我们应该也大概对这个流程有个底了把,无非就是把错误捕捉友好的返回给前端,而不是直接不响应,或者抛出错误,这样是对系统的不友好。0.0