前言:起于环境,先于实践,源于变化,升于思考,再于实践,形于总结——实践至上!
简单回顾:
/*** 基础统一响应类* @param <T>*/@Data public class apiResult<T> {private int code;private String message;private T data;/*** 带有data返回的构造函数* @param code* @param message* @param data*/public apiResult(int code, String message, T data) {this.code = code;this.message = message;this.data = data;}/*** 不带data的构造函数* @param code* @param message*/public apiResult(int code,String message){this.code = code;this.message = message;} }
加工类
/*** 统一响应类实例化工具*/public class apiResultYOUYA {//http成功状态码private static final int OK = HttpStatus.OK.value();//隔着报错状态码private static int NO = HttpStatus.INTERNAL_SERVER_ERROR.value();//基本成功响应public static <T>apiResult<T> success(T data){return new apiResult<>(OK,"操作成功",data);}//自定义信息成功响应public static <T>apiResult<T> success(String message,T data){return new apiResult<>(OK,message,data);}//基础失败响应public static <T>apiResult<T> error(){return new apiResult<>(NO,"系统错误,请联系管理员");}//自定义信息失败响应public static <T>apiResult<T> error(String message){return new apiResult<>(431,message);} }
测试控制类
@GetMapping("/id")public apiResult<UserPageEntity> id(int id){UserPageEntity userPage = userPageServer.UserByID(id);if (userPage == null) {return apiResultYOUYA.error("老登,没有这一号人,是不是记错了");}return apiResultYOUYA.success("成功查询,老登",userPage);
虽然不规范,但是能用
这是我们上一期对方法不生效的解释:我们并没用统一响应覆盖掉的异常报错,这只是简单的响应返回,我们响应统一覆盖掉异常报错才能做到解决
这是因为作者没有重新编译导致的问题,但是这破AI居然认可了我们这种说法,也是没谁了,最后是如何排查出问题的呢?
后来作者写3.0的内容时,顺手刷新了一下,成了
越小的错误,产生越大的bug
正片:
全局统一响应基础三步走
第一步:打上注解@ControllerAdvice
第二步:实现ResponseBodyAdvice<object>接口
第三步:重写方法
@ControllerAdvice public class GlobalApiResult implements ResponseBodyAdvice<Object> {/*** 此Advice是否使用于该返回类型和Converter类型(意思是可以配置多个哦)* @param returnType 返回类型(这里可以获取很多东西, 别被名字误导了)* @param converterType 自动选择的转换器类型* @return 返回true表示将会走接下来的方法(beforeBodyWrite), 否则不会*/@Overridepublic boolean supports(MethodParameter returnType,Class<? extends HttpMessageConverter<?>> converterType) {return false;}/*** HttpMessageConverter转换之前进行的操作* @param body 要转换的body* @param returnType 返回类型* @param selectedContentType 根据请求头协商的ContentType* @param selectedConverterType 自动选择的转换器类型* @param request 当前请求* @param response 当前响应* @return 修改后的响应内容*/@Overridepublic Object beforeBodyWrite(Object body,MethodParameter returnType,MediaType selectedContentType,Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request,ServerHttpResponse response) {return null;} }
三步走完后,我们获取到一个基础的全局响应配置,接下在这两个方法中做文章,便可实现全局统一响应
自定义全局响应:
第一步:先将supports改为true
第二步:将body传入至我们的统一响应工具类中
@ControllerAdvice public class GlobalApiResult implements ResponseBodyAdvice<Object> {/*** 此Advice是否使用于该返回类型和Converter类型(意思是可以配置多个哦)* @param returnType 返回类型(这里可以获取很多东西, 别被名字误导了)* @param converterType 自动选择的转换器类型* @return 返回true表示将会走接下来的方法(beforeBodyWrite), 否则不会*/@Overridepublic boolean supports(MethodParameter returnType,Class<? extends HttpMessageConverter<?>> converterType) {//false -> true 用于测试,正式的时需要修改return true;}/*** HttpMessageConverter转换之前进行的操作* @param body 要转换的body* @param returnType 返回类型* @param selectedContentType 根据请求头协商的ContentType* @param selectedConverterType 自动选择的转换器类型* @param request 当前请求* @param response 当前响应* @return 修改后的响应内容*/@Overridepublic Object beforeBodyWrite(Object body,MethodParameter returnType,MediaType selectedContentType,Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request,ServerHttpResponse response) {//第二步: 将body传入统一响应工具类中的默认成功响应return apiResultYOUYA.success(body);} }
修改我们的测试controller
@RestController public class test {@ResourceUserPageServer userPageServer;/*** 自定义响应信息的运用** @param id* @return*/@GetMapping("/id")public UserPageEntity id(int id){return userPageServer.UserByID(id); }
运行测试结果
运行前,先使用maven的claen生命周期,再编译运行,避免同上面一模一样的错误
来一个完整的增删改查,再体验体验
@RestController @RequestMapping("/test") public class test {@ResourceUserPageServer userPageServer;@GetMapping("/id")public UserPageEntity id(int id) {return userPageServer.UserByID(id);}@PostMapping("/insert")public int insert(@RequestBody UserPageEntity userPageEntity) {return userPageServer.UserInsert(userPageEntity);}@PostMapping("/update")public int update(@RequestBody UserPageEntity userPageEntity) {return userPageServer.UserUpdate(userPageEntity);}@PostMapping("/delete")public int delete(@RequestBody Long[] id) {return userPageServer.USerDelete(id);} }
经典永不过时
测试
无效新增
有效新增
有效查询
无效查询
无效删除
有效删除
无效更新
有效更新
经典CRUD下来,发现没,响应成功的还好说,没响应成功也套用了,也是完成了我们的目标
全局响应了
全局统一响应(无论对错)
那如果配合上局部呢?
就会因为类型的问题导致,那就修改类型
@GetMapping("/id")public apiResult<UserPageEntity> id(int id) {UserPageEntity userPageEntity = userPageServer.UserByID(id);if (userPageEntity == null){return apiResultYOUYA.error("没有该用户,老登");}return apiResultYOUYA.success("查询成功了,老登", userPageEntity);}
局部和全局无法同时纯在,局部>全局,就和交通法一样,地方 大于 全国
除了上面两个例子还有很多,全局作用域和局部作用域
在js中更容易体现,java还有报错
小结:如何快速达到真 · 全局统一响应(无论成功还是失败)
@ControllerAdvice public class GlobalApiResult implements ResponseBodyAdvice<Object> {/*** 此Advice是否使用于该返回类型和Converter类型(意思是可以配置多个哦)* @param returnType 返回类型(这里可以获取很多东西, 别被名字误导了)* @param converterType 自动选择的转换器类型* @return 返回true表示将会走接下来的方法(beforeBodyWrite), 否则不会*/@Overridepublic boolean supports(MethodParameter returnType,Class<? extends HttpMessageConverter<?>> converterType) {//false -> true 用于测试,正式的时需要修改return true;}/*** HttpMessageConverter转换之前进行的操作* @param body 要转换的body* @param returnType 返回类型* @param selectedContentType 根据请求头协商的ContentType* @param selectedConverterType 自动选择的转换器类型* @param request 当前请求* @param response 当前响应* @return 修改后的响应内容*/@Overridepublic Object beforeBodyWrite(Object body,MethodParameter returnType,MediaType selectedContentType,Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request,ServerHttpResponse response) {//第二步: 将body传入统一响应工具类中的默认成功响应return apiResultYOUYA.success(body);} }
第二阶段:
打上断点,测试这个方法起到的作用
当我们触发查询接口时,他自动的触发了这个方法
自动获取了接口的这6个参数
发现没,这个方法自动归类了,不知道是真是假,所以我们修改一下内容进行测试
原来如此,所谓的统一响应的来源是这个,spring web的响应内容就是由这三个大部分组成的,所谓的统一,是对接口的统一,而不是对响应内容的统一
此统一非响应统一,原因是,响应早已经是统一的了
再来一轮测试
@GetMapping("/id")public UserPageEntity id(int id) {return userPageServer.UserByID(id);}
修改测试接口
通过不断的测试,测试,修改内容,作者发现了惊天的秘密(别人早在文档里就写了,你算什么发现!!!!)
下一期说明发现!