统一异常拦截
Spring Boot @RestControllerAdvice 统一异常处理
在做前后端分离的项目时,后端通常都会拆分成多个独立的微服务,这时候就会涉及每个服务返回给前端的数据格式问题了。下面就来实现一个比较常用的数据格式,统一所有服务的返回值格式。
一般返回的数据格式会包括4个部分,第一部分: 请求处理是否成功,第二部分:服务处理结果编码,第三部分:编码对应的文本信息,第四部分:返回值。如下所示:
{
"result": true,
"code": 1000,
"message": "SUCCESS",
"data": {
"lantian": 17,
"qingfen": 16,
"baiyun": 18
}
}
对于异常处理情况,我们也需要统一成上面的格式。如果我们在controller中通过try catch来处理异常的话,会出现一个问题就是每个函数里都加一个Try catch,代码会变的很乱。下面我们就通过spring boot的注解来省略掉controller中的try-catch 帮助我们来封装异常信息并返回给前端,这样用户也不会得到一些奇奇怪怪的错误提示。
{
"result": false,
"code": 3000,
"message": "THIS IS AN UNKNOW EXCEPTION",
"data": null
}
1:定义返回值结构信息(get, set函数省略)
public class CallResultMsg<T> {
private boolean result;
private int code;
private String message;
private T data;
}
2:定义返回值和对应code的信息(get, set函数省略)
public enum CodeAndMsg {
SUCCESS(1000, "SUCCESS"),
METHODFAIL(2000, "ENCOUNTER AN ERROR WHEN EXECUTE METHOD"),
UNKNOWEXCEPTION(3000, "THIS IS AN UNKNOW EXCEPTION");
private int code;
private String msg;
CodeAndMsg(int code, String msg){
this.code = code;
this.msg = msg;
}
}
3:自定义异常
对于一些特别的异常,我们可以自定义Exception和Error Code,这里自定义一个异常(需要继承RuntimeException)
public class UserDefinedException extends RuntimeException {
private CodeAndMsg exception;
public UserDefinedException(CodeAndMsg exception){
this.exception = exception;
}
public CodeAndMsg getException() {
return exception;
}
public void setException(CodeAndMsg exception) {
this.exception = exception;
}
}
4:RestControllerAdvice来捕获全局异常,
@RestControllerAdvice都是对Controller进行增强的,可以全局捕获spring mvc抛的异常。
@ExceptionHandler(value = Exception.class)
ExceptionHandler的作用是用来捕获指定的异常。
@RestControllerAdvice(annotations = RestController.class)
public class UniformReponseHandler<T> {
@ResponseStatus(HttpStatus.OK)
public CallResultMsg sendSuccessResponse(){
return new CallResultMsg(true, CodeAndMsg.SUCCESS, null);
}
@ResponseStatus(HttpStatus.OK)
public CallResultMsg sendSuccessResponse(T data) {
return new CallResultMsg(true, CodeAndMsg.SUCCESS, data);
}
@ExceptionHandler(UserDefinedException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public CallResultMsg sendErrorResponse_UserDefined(Exception exception){
return new CallResultMsg(false, ((UserDefinedException)exception).getException(), null);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public CallResultMsg sendErrorResponse_System(Exception exception){
if (exception instanceof UserDefinedException) {
return this.sendErrorResponse_UserDefined(exception);
}
return new CallResultMsg(false, CodeAndMsg.UNKNOWEXCEPTION, null);
}
}
通过上面的一波操作,我们的controller中就不需要再去写大量的try-catch了,RestControllerAdvice会自动帮助catch,并匹配相应的ExceptionHandler,然后重新封装异常信息,返回值,统一格式返回给前端。
5:ControllerAdvice 和 RestControllerAdvice的区别
@ControllerAdvice 和 @RestControllerAdvice都是对Controller进行增强的,可以全局捕获spring mvc抛的异常。
RestControllerAdvice = ControllerAdvice + ResponseBody
6:测试统一异常捕获功能
@GetMapping("/doTestObject")
public CallResultMsg testObjectReturn(){
Map<String, Integer> map = new HashMap();
map.put("qingfen", 16);
map.put("lantian", 17);
map.put("baiyun", 18);
return new UniformReponseHandler<Map>().sendSuccessResponse(map);
}
@GetMapping("/doTestException/{x}")
public int testExceptionResturn(@PathVariable int x){
if (0 < x && x < 10){
throw new UserDefinedException(CodeAndMsg.METHODFAIL);
} else {
return 1/0;
}
}
返回结果:
{
"result": true,
"code": 1000,
"message": "SUCCESS",
"data": {
"lantian": 17,
"qingfen": 16,
"baiyun": 18
}
}
{
"result": false,
"code": 2000,
"message": "ENCOUNTER AN ERROR WHEN EXECUTE METHOD ",
"data": null
}