参考Spring Boot @RestControllerAdvice 统一异常处理、@RestControllerAdvice构造统一返回值格式和统一异常处理、SpringBoot 使用 beforeBodyWrite 实现统一的接口返回类型
//这些是lombok的注解
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommonResponse<T> {
private boolean success;
private int code;
private String message;
private T data;
public CommonResponse(Integer code, String message, Boolean success) {
this.code = code;
this.message = message;
this.success = success;
}
}
@RestControllerAdvice
public class CommonResponseDataAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
//通过方法参数得到类名, 然后得到类上的annotation,
// 如果被IgnoreResponseAdvice标识就不拦截
if (methodParameter.getDeclaringClass().isAnnotationPresent(
IgnoreResponseAdvice.class
)) {
return false;
}
//方法上被标注,也不拦截
if (methodParameter.getMethod().isAnnotationPresent(
IgnoreResponseAdvice.class
)){
return false;
}
return true;
}
// beforeBodyWrite 即在写入相应之前
// 所以在这里构造统一格式
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
CommonResponse<Object> response = new CommonResponse<>(0,"", true);
if (null == o) {
// 若是null 则不进行处理
} else if (o instanceof CommonResponse) {
// 若返回类型是commonResponse,则不进行修改,
// 这是为了防止对原本的代码产生影响
//(原本的代码中,有些返回的类型可能就是CommonResponse)
response = (CommonResponse<Object>) o;
} else {
response.setData(o);
}
return response;
}
}
@Controller
public class UserController {
@PostMapping("/justTest")
@ResponseBody
public User justTest(@RequestBody User user) {
return user;
}
}
返回结果正如我们的预期,但是如果是错误呢?
我们将代码修改为如下所示,以进行测试
@PostMapping("/justTest")
@ResponseBody
public User justTest(@RequestBody User user) {
int i = 1/0;
return user;
}
再次使用postman进行测试
发现data中是错误信息,但是我们的success字段仍然为true,这不是我们所想要的。
在CommonResponseDataAdvice添加@ExceptionHandler方法
@RestControllerAdvice
public class CommonResponseDataAdvice implements ResponseBodyAdvice {
// 之前的代码省略不显示
// 错误捕捉,一个Controller下多个ExceptionHandler的异常类型不能一样
@ExceptionHandler(value = Exception.class)
public CommonResponse<String> handlerGlobeException(HttpServletRequest request, Exception exception){
CommonResponse<String> response=new CommonResponse<>(0,"发生错误", false);
response.setData(exception.getMessage());
return response;
}
}
我们新建一个自定义一个错误类,一般来说继承Exception或者是其子类 RuntimeException。
可以这样理解这有两个类,
Exception 是某些可以恢复的错误,这些是用户设置什么的犯下的错误。
RunTimeException 是不可以恢复的错误,无能为力,这些是程序员犯下的错误。
public class CommonException extends Exception {
public CommonException(String message) {
super(message);
}
}
在代码中,添加新的错误处理,处理CommonException的错误
@ExceptionHandler(value = CommonException.class)
public CommonResponse<String> handlerCommonException(HttpServletRequest request, Exception exception){
CommonResponse<String> response=new CommonResponse<>(0,"这边是commonException的错误处理", false);
response.setData(exception.getMessage());
return response;
}
@Controller
public class UserController {
@PostMapping("/justTest")
@ResponseBody
public User justTest(@RequestBody User user) {
//假设这里对username进行验证(比如查重),发现用户名与数据库的重复了
if (user.getUserName().equals("重复的用户名")) {
throw new CommonException("用户名重复,这样不行");
} else {
// 如果userName没有重复再进行其他业务操作
}
return user;
}
}
可发现成功触发了我们写在 CommonResponseDataAdvice 中的 commonException 的错误处理