写点什么

统一处理 controller 层接口返回的数据

  • 2021 年 11 月 12 日
  • 本文字数:1929 字

    阅读完需:约 6 分钟

//若未封装 则对其进行封装


return objectCommonResult;


}


}


复制代码


说明:实现 ResponseBodyAdvice 接口 需要重写 supports,beforeBodyWrite 方法;


supports:是否支持给定的控制器方法返回类型和选定的 HttpMessageConverter 类型; 若不支持 则就不会对数据进行做统一处理,就像上面代码,若加了 @ResponseNotIntercept 注解,则不会进行拦截(@ResponseNotIntercept 是自己自定义的一个注解)


参数:returnType:返回类型; converterType:选择的转换器类型


返回:若返回结果为 true,则调用 beforeBodyWrite


beforeBodyWrite:在选择 HttpMessageConverter 之后以及在调用其 write 方法之前调用。


参数:body:你传入的数据;returnType:controller 层方法返回的类型;selectedContentType :通过内容协商选择的内容类型;selectedConverterType:选择要写入响应的转换器类型;request/reponse:当前请求和响应


返回:传入的数据或修改的(可能是新的)实例


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


  • 2.2 编写 contrller 层方法


@RestController


@Slf4j


@RequestMapping("/baseInfo")


public class BaseInfoController {


@Autowired


private BaseInfoService baseInfoService;


/**


  • 添加基本信息

  • @param info

  • @return


*/


@PostMapping("/addBaseInfo")


public BaseInfo addBaseInfo(@RequestBody BaseInfo info){


BaseInfo baseInfo = baseInfoService.addBaseInfo(info);


return baseInfo;


}


}


复制代码


控制层返回的是一个对象,业务层 数据层方法省略 对只想执行后返回的结果做了统一的处理:



  • 2.3 统一返回对象


@Data


@Slf4j


public class CommonResult<T> {


private String code;


private String message;


private T Data;


public CommonResult() {


}


public CommonResult(T data) {


Data = data;


}


/**


  • 若只传入 code 码 默认传入的数据为 null

  • @param rc


*/


public CommonResult(ResultCode rc) {


this(rc, null);


}


public CommonResult(ResultCode rc, T data) {


this.code = rc.getCode();


this.message = rc.getMsg();


this.Data = data;


}


public static<T> CommonResult<T> errorResult(ResultCode rc,T data){


CommonResult<T> commonResult = new CommonResult<>();


commonResult.code = rc.getCode();


commonResult.message = rc.getMsg();


commonResult.Data = data == null?(T) "" :data;


log.error("{}",commonResult);


return commonResult;


}


}


复制代码


ResultCode 是自己自定的一些枚举类 例如部分:


3. 常见错误分析

但是就如上面这些就完全正确了吗?其实不然 若在 controller 层方法返回字符串会出现什么情况?请看:


@PostMapping("/test")


public String addBaseInfo(){


return "我返回的是一个字符串";


}


复制代码



控制台报错:


org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: com.flscode.publicApi.Response.CommonResult cannot be cast to java.lang.String


Caused by: java.lang.ClassCastException: com.flscode.publicApi.Response.CommonResult cannot be cast to java.lang.String


解决


分析: 正常数据返回:



字符串数据返回 打断点:




原因: SpringMVC 默认会注册一些自带的HttpMessageConvertor(从先后顺序排列分别为 ByteArrayHttpMessageConverter、StringHttpMessageConverter、ResourceHttpMessageConverter,SourceHttpMessageConverter、AllEncompassingFormHttpMessageConverter),后端服务使用 Restful API 的形式,前后端得规范一般是 json 格式,SpringMVC 自带MappingJackson2HttpMessageConverter,在依赖中引入 jackson 包后,容器会把MappingJackson2HttpMessageConverter自动注册到 converter 链的末尾 (这端话来自:blog.csdn.net/weixin_4433…


因此 从上面两张图对比可以看出,此处得方法是要去循环遍历 HttpMessageConverter 集合,如果对应得转换器能够使用 则会使用该转换器,当你返回得数据是字符串时,因为 StringHttpMessageConverter 会先被遍历到,这时会认为 StringHttpMessageConverter 可以使用,因此在 ResponseBodyAdvice 封装数据时就会报错


修改后:


@Override


public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {


if (body instanceof CommonResult) return body;


CommonResult<Object> objectCommonResult = new CommonResult<>(ResultCode.SUCCESS, body);


if (body instanceof String){


String s = JSON.toJSONString(new CommonResult<>(ResultCode.SUCCESS, body));


return s;


}

评论

发布
暂无评论
统一处理controller层接口返回的数据