前言:
我们在开始项目时,要和前端约定好接口的相关结构,其中约定接口返回数据的格式是很重要的,涉及到数据能否正确传输,而我们后端返回统一的数据格式,可以为前后端的交流以及项目的开发省去很多的麻烦
快速入门:
响应通知类 - 统⼀数据返回格式(接口正确返回响应)
统⼀的数据返回格式使⽤ @ControllerAdvice 和 ResponseBodyAdvice 的⽅式实现 @ControllerAdvice 表⽰响应通知类 添加类 ResponseAdvice ,实现 ResponseBodyAdvice 接⼝,并在类上添加 @ControllerAdvice 注解
java
@ControllerAdvice
@Slf4j
public class ResponseAdvice implements ResponseBodyAdvice {
private ObjectMapper objectMapper=new ObjectMapper();
// supports 方法开启 beforeBodyWrite 方法
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
// beforeBodyWrite ⽅法:就是对响应进⾏具体操作处理
// body 代表接口原本要返回的数据
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
log.info("进行统一数据返回格式body:{}",body);
//当接口原本要返回的数据类型就是 Result 时,就不继续封装成 Result 对象了
if(body instanceof Result){
return body;
}
//当接口原本要返回的数据类型是 String 时,要进行特殊处理,要把返回的 Result 对象解析成 json 格式的字符串进行返回
if(body instanceof String){
return objectMapper.writeValueAsString(Result.success(body));
}
return Result.success(body);
}
}
加 @ControllerAdvice 注解才能将 ResponseAdvice 的对象交给 Spring 的 IoC 容器进行管理,才能对全局的接口起作用,@ControllerAdvice 注解不属于五大注解,为什么可以起到相同的作用呢,因为 @ControllerAdvice 注解是基于 @Component 注解实现的
重写 ResponseBodyAdvice 接口里的 supports 方法和 beforeBodyWrite 方法
supports⽅法:判断是否要执⾏ beforeBodyWrite⽅法. true 为执⾏, false 不执⾏.
beforeBodyWrite 方法:统一接口数据返回格式的具体处理细节
beforeBodyWrite 方法中的参数 body 就是接口原本要返回的数据内容,我们要将这个数据内容重新封装成 Result 类型的对象,再返回给前端,这样前端接收到的数据都是 Result 类型的格式
在统一接口数据返回格式时有两种特殊情况:
(1).接口要返回的类型已经是规定的 Result 类型了,此时就不需要再进行封装,直接返回即可
(2).接口返回的类型是 String 类型,此时要进行特殊处理,在将 String 类型的数据封装成 Result 类型以后,还需要将 Result 类型的对象解析成 json 格式的字符串才能返回,要不然会报错,这种特殊情况是 Spring Boot 的源码问题
要注意,响应通知类 统一的是接口正确返回响应时的数据格式,要想统一异常返回格式需要看下面介绍的 异常处理器
异常处理器 - 统一异常返回格式:
统⼀异常返回格式使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的, @ControllerAdvice 表⽰控制器通知类, @ExceptionHandler 是异常处理器,两个结合表⽰当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件
java
//异常处理器
//统一异常返回格式
@ControllerAdvice
//加上 @ResponseBody 注解 Spring 才知道返回的是数据,要不然就会去寻找对应 URL 的网页
@ResponseBody
public class ErrorAdvice {
//异常都是继承于 Exception 类的,所以使用 Exception 就可以捕获到 Exception 及其所有子类异常
//当然也可以更具体的捕获异常,进行处理
@ExceptionHandler
public Object hander(Exception e){
return Result.fail(e.getMessage());
}
//专门捕获空指针异常进行处理
@ExceptionHandler
public Object hander(NullPointerException e){
return Result.fail("发⽣NullPointerException:"+e.getMessage());
}
//专门捕获运算异常进行处理
@ExceptionHandler
public Object hander(ArithmeticException e){
return Result.fail("发⽣ArithmeticException:"+e.getMessage());
}
}
加 @ControllerAdvice 注解才能将 ErrorAdvice 的对象交给 Spring 的 IoC 容器进行管理,才能对全局的接口起作用,@ControllerAdvice 注解不属于五大注解,为什么可以起到相同的作用呢,因为 @ControllerAdvice 注解是基于 @Component 注解实现的
加 @ResponseBody 注解是向 Spring 说明返回是数据而不是页面,要是没有加该注解,Spring 就会去以返回的数据作为 url 去寻找对应的页面,就会报 404 错误
自定义方法 hander 里的参数表示要捕获的异常,当接口中出现对应的异常或子类异常后就会以设定好的格式进行返回,如上的代码,当捕获到对应异常以后,就封装成 Result 的对象进行返回,统一了异常返回的格式