网站模板安全管理系统,做景观要知道哪些网站,网站的互动功能,济南专业做网站公司统一的标准数据格式好处
SpringBoot返回统一的标准数据格式主要有以下几点好处#xff1a; 增强接口的可读性和可维护性#xff0c;使得前端开发人员能够更加清晰地理解接口返回的数据结构#xff0c;从而提高开发效率。 降低前后端耦合度#xff0c;当后端需要修改返回数…统一的标准数据格式好处
SpringBoot返回统一的标准数据格式主要有以下几点好处 增强接口的可读性和可维护性使得前端开发人员能够更加清晰地理解接口返回的数据结构从而提高开发效率。 降低前后端耦合度当后端需要修改返回数据结构时只需要调整统一的数据格式而不用修改大量的前端代码。 有利于统一异常处理对于出错时的返回数据格式也是一致的便于前端统一处理错误信息。 当接口版本的升级和兼容时可以通过统一的数据格式进行向下兼容或者向上兼容减少接口变更带来的影响
格式不同的痛楚
一般情况下SpringBoot服务的返回格式有如下几种
第一种返回String
GetMapping(/hello)
public String getStr() {return hello;
}此时调用接口获取到的返回值是这样
hello第二种返回自定义对象
GetMapping(/aniaml)
public Aniaml getAniaml(){Aniaml aniaml new Aniaml(1,pig);return aniaml;
}此时调用接口获取到的返回值是这样
{id: 1,name: pig
}第三种接口异常
GetMapping(/error)
public int error(){int i 10/0;return i;
}此时调用接口获取到的返回值是这样
{timestamp: 2021-07-08T08:05:15.42300:00,status: 500,error: Internal Server Error,path: /error
}看了上边的几种情况不难发现一个接口在不同情况下返回的数据格式竟然截然不同那作为API的使用方估计就要骂娘了。此时返回统一的标准数据格式就显得很有必要。
标准格式
一个标准的返回格式应包含以下三部分 Status状态由后端统一定义各种返回结果的状态码。 Message描述描述本次接口调用的结果信息。 Data数据包含本次返回的具体数据内容。
{status:100,message:操作成功,data:hello
}当然了这并不是绝对的在有了主要的字段后可以按需加入其他扩展值比如我们就在返回对象中添加了接口调用时间timestamp等。
定义返回对象
Data
public class ResultDataT {private int status;private String message;private T data;private long timestamp ;public ResultData (){this.timestamp System.currentTimeMillis();}public static T ResultDataT success(T data) {ResultDataT resultData new ResultData();resultData.setStatus(ReturnCode.RC100.getCode());resultData.setMessage(ReturnCode.RC100.getMessage());resultData.setData(data);return resultData;}public static T ResultDataT fail(int code, String message) {ResultDataT resultData new ResultData();resultData.setStatus(code);resultData.setMessage(message);return resultData;}}定义状态码
public enum ReturnCode {/**操作成功**/RC100(100,操作成功),/**操作失败**/RC999(999,操作失败),/**服务限流**/RC200(200,服务开启限流保护,请稍后再试!),/**服务降级**/RC201(201,服务开启降级保护,请稍后再试!),/**热点参数限流**/RC202(202,热点参数限流,请稍后再试!),/**系统规则不满足**/RC203(203,系统规则不满足要求,请稍后再试!),/**授权规则不通过**/RC204(204,授权规则不通过,请稍后再试!),/**access_denied**/RC403(403,无访问权限,请联系管理员授予权限),/**access_denied**/RC401(401,匿名用户访问无权限资源时的异常),/**服务异常**/RC500(500,系统异常请稍后重试),CLIENT_AUTHENTICATION_FAILED(1001,客户端认证失败),USERNAME_OR_PASSWORD_ERROR(1002,用户名或密码错误),UNSUPPORTED_GRANT_TYPE(1003, 不支持的认证模式);/**自定义状态码**/private final int code;/**自定义描述**/private final String message;ReturnCode(int code, String message){this.code code;this.message message;}public int getCode() {return code;}public String getMessage() {return message;}
}统一返回格式
经过上边我们定义的数据格式再次调用API在Controller层通过ResultData.success()对返回结果进行包装后返回给前端。
GetMapping(/hello)
public String getStr() {return ResultData.success(hello);
}此时调用接口获取到的返回值已经是标准的格式符合我们预期的效果。
{status: 100,message: hello,data: null,timestamp: 1625736481648
}最大的弊端就是我们后面每写一个接口都需要调用ResultData.success()这行代码对结果进行包装重复劳动浪费体力而且还很容易被其他老鸟给嘲笑。所以呢我们需要对代码进行优化目标就是不要每个接口都手工制定ResultData返回值。
高级实现方式
要优化这段代码很简单我们只需要借助SpringBoot提供的ResponseBodyAdvice即可。 “ ResponseBodyAdvice的作用拦截Controller方法的返回值统一处理返回值/响应体一般用来统一返回格式加解密签名等等。 ” 先来看下ResponseBodyAdvice的源码 public interface ResponseBodyAdviceT {/*** 是否支持advice功能* true 支持false 不支持*/boolean supports(MethodParameter var1, Class? extends HttpMessageConverter? var2);/*** 对返回的数据进行处理*/NullableT beforeBodyWrite(Nullable T var1, MethodParameter var2, MediaType var3, Class? extends HttpMessageConverter? var4, ServerHttpRequest var5, ServerHttpResponse var6);
}我们只需要编写一个具体实现类即可
/*** author jam* date 2021/7/8 10:10 上午*/
RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdviceObject {Autowiredprivate ObjectMapper objectMapper;Overridepublic boolean supports(MethodParameter methodParameter, Class? extends HttpMessageConverter? aClass) {return true;}SneakyThrowsOverridepublic Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class? extends HttpMessageConverter? aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {if(o instanceof String){return objectMapper.writeValueAsString(ResultData.success(o));} return ResultData.success(o);}
}需要注意两个地方RestControllerAdvice注解
RestControllerAdvice是RestController注解的增强可以实现三个方面的功能 全局异常处理 全局数据绑定 全局数据预处理
String类型判断
if(o instanceof String){return objectMapper.writeValueAsString(ResultData.success(o));
} 这段代码一定要加如果Controller直接返回String的话SpringBoot是直接返回故我们需要手动转换成json。 经过上面的处理我们就再也不需要通过ResultData.success()来进行转换了直接返回原始数据格式SpringBoot自动帮我们实现包装类的封装。
GetMapping(/hello)
public String getStr(){return hello;
}此时我们调用接口返回的数据结果为
GetMapping(/hello)
public String getStr(){return hello;
}是不是感觉很完美别急还有个问题在等着你呢。
接口异常问题
此时有个问题由于我们没对Controller的异常进行处理当我们调用的方法一旦出现异常就会出现问题比如下面这个接口
GetMapping(/wrong)
public int error(){int i 9/0;return i;
}