统一处理 controller 层接口返回的数据
//若未封装 则对其进行封装
return objectCommonResult;
}
}
复制代码
说明:实现 ResponseBodyAdvice 接口 需要重写 supports,beforeBodyWrite 方法;
supports:是否支持给定的控制器方法返回类型和选定的 HttpMessageConverter 类型; 若不支持 则就不会对数据进行做统一处理,就像上面代码,若加了 @ResponseNotIntercept 注解,则不会进行拦截(@ResponseNotIntercept 是自己自定义的一个注解)
参数:returnType:返回类型; converterType:选择的转换器类型
返回:若返回结果为 true,则调用 beforeBodyWrite
beforeBodyWrite:在选择 HttpMessageConverter 之后以及在调用其 write 方法之前调用。
参数:body:你传入的数据;returnType:controller 层方法返回的类型;selectedContentType :通过内容协商选择的内容类型;selectedConverterType:选择要写入响应的转换器类型;request/reponse:当前请求和响应
返回:传入的数据或修改的(可能是新的)实例
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;
}
评论