Spring:项目中的统一异常处理和自定义异常
介绍异常的处理方式。在项目中,都会进行自定义异常,并且都是需要配合统一结果返回进行使用。
1.背景引入
(1)背景介绍
为什么要处理异常?如果不处理项目中的异常信息,前端访问我们后端就是显示访问失败的,所以我们需要处理。但是单单处理还不够,还需要将信息返回给前端;因为异常是一类问题,所以我们可以统一进行处理,也就是统一异常处理。
(2)没有处理异常时
看一段代码:
@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {
@RequestMapping("/hello")
public String hello() {
log.info("我被前端调用了,嘤嘤嘤~");
int a = 10/0;
return "hello";
}
}
通过url进行访问:
后端日志:
所以这就是没有进行异常处理的后果
(3)简单处理异常后
下面这段代码就会对异常进行捕获,并且返回异常的具体信息
@Slf4j
@ResponseBody
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(Exception.class)
public String exception(Exception e) {
log.warn(e.getMessage());
return e.getMessage();
}
}
前端:
这样前端就知道了明确的异常信息,但是实际异常不会单独使用,都是作为一个Message封装到统一结果中进行返回。
2.异常使用方法
我们先在代码中定义一个简单的统一结果返回,用于介绍和学习异常
import lombok.Data;
@Data
public class Result {
private String message;
private int code;
public Result(String message,int code) {
this.message = message;
this.code = code;
}
public static Result fail(String message) {
return new Result(message,1314);
}
}
(1)统一异常模版
controller:
import lombok.extern.slf4j.Slf4j;
import org.ljy.testdemo.common.Result;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {
@RequestMapping("/hello")
public String hello() {
int a = 10/0;
return "hello";
}
@RequestMapping("/heihei")
public Result heihei() {
return Result.fail("只因你实在是太美~");
}
}
异常捕获:
import lombok.extern.slf4j.Slf4j;
import org.ljy.testdemo.common.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j
@ResponseBody
@RestControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler
public Result exception(Exception e) {
log.error(e.getMessage(), e);
return Result.fail(e.getMessage());
}
}
我们通过前端就行访问:
即时后端发生了异常,前端也能收到格式化的数据,大大提高了可读性。
(2)注解解析
写法一:类@RestControllerAdvice + 方法@ExceptionHandler
表示该类下的所有方法返回的都是数据
写法二:类@ControllerAdvice + 方法@ResponseBody + 方法@ExceptionHandler
表示该方法返回数据
写法三:类@ControllerAdvice + 类@ResponseBody + 方法@ExceptionHandler
表示该类下的所有方法返回的都是数据
其他写法:可以指定捕获异常的类型,也就是在@ExceptionHandler后面加上括号,指定异常的对象
@Slf4j
@RestControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(Exception.class)
public Result exception(Exception e) {
log.error(e.getMessage(), e);
return Result.fail(e.getMessage());
}
}
为什么要加上@ResponseBody注解,不加的时候默认返回视图,就会产生异常,也就是下面的效果
3.使用自定义异常
这里的自定义异常也就是定义一个异常类,然后作为@ExceptionHandler捕获的对象
(1)先自定义一个普通的异常
步骤:实现Exception类或者其子类,然后写构造方法(记得先初始化父类),可以看情况重写几个方法
于是我们得到下面的自定义异常类
public class ApplicationException extends RuntimeException{
//自定义的错误结果(里面包含错误码和错误信息)
protected Result errorResult;
//用于throw new ApplicationException(Result.fail("我走的是构造方法"))这种情况
public Result getErrorResult() {
return errorResult;
}
/**
* 构造方法 用于填充信息
*/
public ApplicationException(Result errorResult) {
super(errorResult.getMessage());
this.errorResult = errorResult;
}
public ApplicationException(String message) {
super(message);
}
public ApplicationException(Throwable cause) {
super(cause);
}
public ApplicationException(String message, Throwable cause) {
super(message, cause);
}
}
(2)再定义全局异常处理器
这里的全局异常处理器就是上面的统一异常处理,只需要多捕获一个自定义异常就可以了。
import lombok.extern.slf4j.Slf4j;
import org.ljy.testdemo.common.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j
@ResponseBody
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(ApplicationException.class)
public Result applicationExceptionHandler (ApplicationException e) {
e.printStackTrace();
// 打印日志
if (e.getErrorResult() != null) {
return e.getErrorResult();
}
// 一般不会为null,构造方法已经限制住了,但是保险一些
if (e.getMessage() == null || e.getMessage().equals("")) {
return Result.fail(e.getMessage());
}
// 返回具体的异常信息
return Result.fail(e.getMessage());
}
//兜底捕获异常
@ExceptionHandler(Exception.class)
public Result exception(Exception e) {
log.error(e.getMessage(), e);
return Result.fail(e.getMessage());
}
}
大致情况就这么写,接下来解析一下统一异常中的几种校验情况