在当前的主流环境下,大部分项目都是基于restful的接口来开发的。那么对于接口的返回形式很多时候就会有各种方式,比如说,要不要在最外层包装一层?其实这个主要是根据项目的情况来处理,就我个人而言,我觉得内部业务是不需要包装的,但是按照restful的风格,要么没有返回值,如果有返回值一定是一个Object,不要返回一个string这种就可以了。然而,如果是对外的接口给第三方使用之类的,还是包装一层比较好,毕竟最外层的几个基础字段更便于理解。
1.直接返回数据,用httpStatus表示成功与否
我们要返回这么一结果
{
"title": "三国演义",
"content": "测试"
}
在controller中直接返回对象即可
@GetMapping(value = "one")
public Article queryOne(){
return Article.builder().title("三国演义").content("测试").build();
}
结果如下
在成功返回数据的时候,我们只要拿到这个结果就可以了,但是对于异常的处理,我们需要用httpStatus的值类判断。
定义一个错误对象
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class ErrorResponse {
private String code;
private String message;
}
定义一个全局的异常捕获
@RestControllerAdvice
public class ErrorHandler {
@ExceptionHandler(value = ApiException.class)
public ErrorResponse error(ApiException ex, HttpServletResponse response){
response.setStatus(460);
return ErrorResponse.builder().code(ex.getCode()).message(ex.getMessage()).build();
}
}
抛出一个异常试试
@GetMapping(value = "error")
public void error(){
throw new ApiException("500","error message");
}
这种方式,只需要在httpclient 使用response的拦截器处理下httpStatus值即可,如果是200则返回数据,如果不是则处理异常。
2.包装一层,所有的httpStatus 都是200,根据返回值的某字段来判断
另外一种方式,就是在返回的数据上包装一层,客户端根据success字段来判断请求是否成功。
首先,我们定义一个统一的返回对象,不管返回的是什么,泛型来解决。
@Data
public class DataResponse<T> {
private Boolean success;
private T data;
}
写一个方法测试下
@GetMapping(value = "res/one")
public DataResponse<Article> queryOneRes(){
Article article = Article.builder().title("三国演义").content("测试").build();
DataResponse<Article> response = new DataResponse<>();
response.setSuccess(true);
response.setData(article);
return response;
}
可以看到返回结果已经是被包装过的
那么,如果全局都是要这种格式的,难道每个函数都要这么写嘛?ResponseBodyAdvice 可以帮我们做response的包装工作。
@RestControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
@ExceptionHandler(value = ApiException.class)
public ErrorResponse error(ApiException ex, HttpServletResponse response){
return ErrorResponse.builder().success(false).code(ex.getCode()).message(ex.getMessage()).build();
}
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return !Objects.equals(returnType.getParameterType(),ErrorResponse.class);
}
@Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
DataResponse<Object> response1 = new DataResponse<>();
response1.setSuccess(true);
response1.setData(body);
return response1;
}
}
此时再来看下方式一的两个返回值
这样,我们就可以通过配置方法给所有的返回值加上包装。