SpringBoot业务开发 03、Springboot异常处理
@[toc]
前言
本篇博客是SpringBoot处理异常的解决方案,若文章中出现相关问题,请指出!
所有博客文件目录索引:博客目录索引(持续更新)
一、Springboot处理异常的三种处理方式
1、在Controller上标注@ExceptionHandler异常。
2、全级别异常处理,通过实现HandlerExceptionResolver
接口,接着重写方法,在该方法中处理所有的异常!
3、全局级别异常处理器:@ControllerAdvice+@ExceptionHandler
,推荐使用这种方式!!!
二、介绍第三种方法(@ControllerAdvice+@ExceptionHandler)
2.1、全局捕捉异常处理的相关注解
现在对于异常处理普通方法使用@ControllerAdvice
+@ExceptionHandler
。
介绍几个注解的含义:
-
@ControllerAdvice
:捕捉所有标注@Controller类抛出的异常。 -
@ExceptionHandler
:标记了使用 errorHandlerOverJson() 方法来处理 GlobalErrorInfoException 异常。通常用于指定拦截指定的异常。 -
@RestControllerAdvice
:该注解其实是由@ControllerAdvice
与@ResponseBody
组成的,我们一般后台捕捉到异常时都会向前端返回json字符串,所有可以直接使用该注解来标注于类,而不用在每个方法上加@ResponseBody
。
2.2、响应码设计
ErrorInfoInterface
:错误码接口规范,得到code响应码,message响应描述。CityErrorInfoEnum
与GlobalErrorInfoEnum
:这两个都是枚举类,都继承了错误码接口规范,我们可以创建多个枚举类来表示不同的情况描述,这两个类一个表示城市错误信息,另一个表示去全局错误信息枚举类!!!
BaseErrorInfoInterface.java
:错误码接口规范
/**
* @author changlu
* @date 2021/07/22 17:03
**/
public interface BaseErrorInfoInterface {
/**
* 得到错误码
* @date 2021/07/22 17:04
* @return java.lang.String
*/
String getResultCode();
/**
* 得到错误信息
* @date 2021/07/22 17:05
* @return java.lang.String
*/
String getResultMsg();
}
commonInfoEnum.java
:普通错误枚举类
public enum CommonEnum implements BaseErrorInfoInterface{
SUCCESS("200", "成功"),
BODY_NOT_MATCH("400", "请求的数据格式不符"),
SIGNATURE_NOT_MATCH("401", "请求的数字签名不匹配!"),
OT_FOUND("404", "未找到该资源!"),
INTERNAL_SERVER_ERROR("500", "服务器内部错误!"),
SERVER_BUSY("503", "服务器正忙,请稍后再试!"),
NULLPOINTER_ERROR("1001","空指针异常");
//错误码
private String resultCode;
//描述信息
private String resultMsg;
CommonEnum(String resultCode, String resultMsg) {
this.resultCode = resultCode;
this.resultMsg = resultMsg;
}
@Override
public String getResultCode() {
return resultCode;
}
@Override
public String getResultMsg() {
return resultMsg;
}
}
之后我们若是出现了某种异常情况,可直接拿到对应的枚举实例,也就直接拿到了code与message。
2.3、结果响应类(最终返回给前端)
该类有三个值组成:code
、message
、data
,分别是响应码、描述信息以及data数据(是一个对象)。
最终通过转成JSON字符串形式返回给前端!
ResultBody.java
/**
* @author changlu
* @date 2021/07/22 17:15
**/
@Data
public class ResultBody {
/**
* 响应码
*/
private String code;
/**
* 响应消息
*/
private String message;
/**
* 响应结果
*/
private Object result;
public ResultBody() {
}
/**
* 响应码与响应结果封装
*/
public ResultBody(BaseErrorInfoInterface baseErrorInfoInterface) {
this.code = baseErrorInfoInterface.getResultCode();
this.message = baseErrorInfoInterface.getResultMsg();
}
/**
* 成功
* @param data 数据
* @return xyz.changlu.util.ResultBody
*/
public static ResultBody success(Object data){
ResultBody resultBody = new ResultBody(CommonEnum.SUCCESS);
resultBody.setResult(data);
return resultBody;
}
/**
* 错误
* @param baseErrorInfoInterface 枚举类
* @return xyz.changlu.util.ResultBody
*/
public static ResultBody error(BaseErrorInfoInterface baseErrorInfoInterface){
ResultBody resultBody = new ResultBody(baseErrorInfoInterface);
resultBody.setResult(null);
return resultBody;
}
/**
* 错误
* @param code 状态码
* @param message 描述信息
* @return xyz.changlu.util.ResultBody
*/
public static ResultBody error(String code,String message){
ResultBody resultBody = new ResultBody();
resultBody.setCode(code);
resultBody.setMessage(message);
resultBody.setResult(null);
return resultBody;
}
}
2.4、核心:自定义异常类与全局异常捕捉类
自定义异常类:通常自定义异常类继承运行时异常RuntimeException,因为这一类异常是不会强制程序员写try-catch进行捕获的,所以我们可以定义一些来进行手动抛出,之后供全局异常进行捕捉,可设置多个。
全局异常捕捉类:该类用于捕捉@controller注解标注的类抛出的异常,包含自定义异常以及其他异常,我们都可以进行单独编写,一般就这两种。
自定义异常类
public class MsgException extends RuntimeException{
/**
* 错误代码
*/
private String errorCode;
/**
* 错误信息
*/
private String errorMsg;
public MsgException() {
}
public MsgException(String errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public MsgException(String message,String errorCode, String errorMsg) {
super(message);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
//传入错误信息接口(如枚举类)
public MsgException(BaseErrorInfoInterface baseErrorInfoInterface,Throwable cause){
super(baseErrorInfoInterface.getResultCode(), cause);
this.errorCode = baseErrorInfoInterface.getResultCode();
this.errorMsg = baseErrorInfoInterface.getResultMsg();
}
public MsgException(Throwable cause, String errorCode, String errorMsg){
super(errorCode, cause);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
//set/get方法
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
@Override
public synchronized Throwable fillInStackTrace() {
return super.fillInStackTrace();
}
}
全局异常捕捉类
当出现异常后,我们依旧会向前端进行响应返回数据!
/**
* @author Administrator
* @date 2021/07/22 17:27
**/
@RestControllerAdvice
public class MyExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(MyExceptionHandler.class);
/**
* 自定义的业务异常(自己向外抛出的异常)
* @param HttpServletRequest servlet请求
* @param ex 自定义抛出异常
* @return xyz.changlu.util.ResultBody
*/
@ExceptionHandler(value = MsgException.class)
public ResultBody msgExceptionHandler(HttpServletRequest request,MsgException ex){
logger.error("自定义的业务异常拦截处理,原因是:" + ex.getErrorMsg());
return ResultBody.error(ex.getErrorCode(),ex.getErrorMsg());
}
/**
* 空指针异常处理程序
*
* @param req 要求的事情
* @param e e
* @return {@link ResultBody}
*/
@ExceptionHandler(value = NullPointerException.class)
public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e) {
logger.error("空指针异常处理!原因是:", e.getMessage());
return ResultBody.error(CommonEnum.NULLPOINTER_ERROR);
}
/**
* 其他异常处理程序
*
* @param req 要求的事情
* @param e e
* @return {@link ResultBody}
*/
@ExceptionHandler(value = Exception.class)
public ResultBody exceptionHandler(HttpServletRequest req, Exception e) {
logger.error("其他异常处理程序!原因是:", e.getMessage());
return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
}
}
测试
我们来编写一些Controller来测试全局异常捕捉类是否能够捕捉到指定的异常:
/**
* @author changlu
* @date 2021/07/22 17:38
**/
@RestController
public class UserController {
//测试自定义异常
@PostMapping("/user")
public boolean add(User user){
System.out.println("开始新增....");
if(user.getName() == null){
//抛出自定义异常
throw new MsgException("-1","用户姓名不能为空!");
}
return true;
}
//测试空指针异常
@DeleteMapping("/user/{id}")
public boolean delete(@PathVariable("id")Integer id){
System.out.println("开始删除....");
//抛出空指针
String str = null;
str.equals("123");
return true;
}
//测试其他异常
@PutMapping("/user/{id}")
public boolean update(@PathVariable("id")Integer id,User user){
System.out.println("开始更新....");
//程序自己出错
Integer.parseInt("abc123");
return true;
}
@GetMapping("/user/{id}")
public ResultBody query(@PathVariable("id")Integer id){
System.out.println("开始查询....");
return ResultBody.success(null);
}
}
参考文章
[1]. Spring Boot HTTP over JSON 的错误码异常处理
[2]. Spring 异常处理三种方式 @ExceptionHandler:包含原理介绍
- 点赞
- 收藏
- 关注作者
评论(0)