正文
supports
(MethodParameter returnType, Class extends HttpMessageConverter>> converterType)
;
@Nullable
T
beforeBodyWrite
(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class extends HttpMessageConverter>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response)
;
}
-
supports:
判断是否要交给 beforeBodyWrite 方法执行,ture:需要;false:不需要
-
beforeBodyWrite:
对 response 进行具体的处理。
// 如果引入了swagger或knife4j的文档生成组件,这里需要仅扫描自己项目的包,否则文档无法正常生成
@RestControllerAdvice(basePackages = "com.example.demo")
publicclassResponseAdviceimplementsResponseBodyAdvice<Object> {
@Override
publicbooleansupports(MethodParameter returnType, Class extends HttpMessageConverter>> converterType){
// 如果不需要进行封装的,可以添加一些校验手段,比如添加标记排除的注解
returntrue;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class extends HttpMessageConverter>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response){
// 提供一定的灵活度,如果body已经被包装了,就不进行包装
if (body instanceof Result) {
return body;
}
return Result.success(body);
}
}
经过这样改造,既能实现对 Controller 返回的数据进行统一包装,又不需要对原有代码进行大量的改动。
处理
cannot be cast to java.lang.String
问题
如果直接使用
ResponseBodyAdvice
,对于一般的类型都没有问题,当处理字符串类型时,会抛出
xxx.包装类 cannot be cast to java.lang.String
的类型转换的异常。
在
ResponseBodyAdvice
实现类中 debug 发现,只有 String 类型的
selectedConverterType
参数值是
org.springframework.http.converter.StringHttpMessageConverter
,而其他数据类型的值是
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
。
现在问题已经较为清晰了,因为我们需要返回一个 Result 对象。
所以使用
MappingJackson2HttpMessageConverter
是可以正常转换的。
而使用
StringHttpMessageConverter
字符串转换器会导致类型转换失败。
现在处理这个问题有两种方式:
①在
beforeBodyWrite
方法处进行判断,如果返回值是 String 类型就对 Result 对象手动进行转换成 JSON 字符串,另外方便前端使用,最好在
@RequestMapping
中指定
ContentType
。
@RestControllerAdvice(basePackages = "com.example.demo")
publicclassResponseAdviceimplementsResponseBodyAdvice<Object> {
...
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class extends HttpMessageConverter>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response){
// 提供一定的灵活度,如果body已经被包装了,就不进行包装
if (body instanceof Result) {
return body;
}
// 如果返回值是String类型,那就手动把Result对象转换成JSON字符串
if (body instanceof String) {
try {
returnthis.objectMapper.writeValueAsString(Result.success(body));
} catch (JsonProcessingException e) {
thrownew RuntimeException(e);
}
}
return Result.success(body);
}
...
}
@GetMapping(value = "/returnString", produces = "application/json; charset=UTF-8")
public String returnString(){
return"success";
}
②修改
HttpMessageConverter
实例集合中
MappingJackson2HttpMessageConverter
的顺序。因为发生上述问题的根源所在是集合中
StringHttpMessageConverter
的顺序先于
MappingJackson2HttpMessageConverter
的,调整顺序后即可从根源上解决这个问题。
网上有不少做法是直接在集合中第一位添加
MappingJackson2HttpMessageConverter