SpringBoot对String类型返回值的处理
问题:
有类似如下返回值接口:
1 |
|
请求返回 json
格式数据,返回值应为:"hello"
,但实际收到的数据为:hello
原因:
SpringBoot的Message响应处理流程
a.
test()
接口执行并返回String
值b.
1
2
3HandlerMethodReturnValueHandlerComposite.handleReturnValue(Object returnValue, MethodParameter returnType, …) {
selectHandler()
}c.
1
2
3RequestResponseBodyMethodProcessor.handleReturnValue() {
writeWithMessageConverters()
}writeWithMessageConverters()
在RequestResponseBodyMethodProcessor
的父类AbstractMessageConverterMethodProcessor
中,其中第一个部分1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18protected <T> void writeWithMessageConverters( T value, MethodParameter returnType, ...)throws IOException ... {
Object body;
Class<?> valueType;
Type targetType;
// 这里直接对字符序列类型数据写入body
if (value instanceof CharSequence) {
body = value.toString();
valueType = String.class;
targetType = String.class;
}
else {
body = value;
valueType = getReturnValueType(body, returnType);
targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
}
... ...对于字符序列的返回值做了特殊处理,直接将值toString()写入body中
第二个部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19for (HttpMessageConverter<?> converter : this.messageConverters) {
... ...
if (... converter.canWrite(...)) {
body = getAdvice().beforeBodyWrite(...);
if (body != null) {
... ...
if (genericConverter != null) {
genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}
else {
((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
}
}
else {
logger ... ...
}
return; // 直接返回终止遍历
}
}进行HttpMessageConverters的遍历调用,messageConverters如下:
对当前返回值进行类型对应Converter适配并在能够处理时,进行处理并返回值。
两个
StringHttpMessageConverters
:问题分析
writeWithMessageConverters() 这个方法对字符串的默认处理,以及 HttpMessageConverters 的默认顺序,以及处理返回机制,导致了String类型返回值不能呗 Jackson 的 MessageConverter 处理
解决方案:
对返回String类型值的接口,在返回的时候进行特殊处理,例如使用fastJson:
1
return JSON.toJSONString(returnValue)
【推荐】对返回值进行封装成对象就不会出现问题了,如下
1
2
3
4
5{
"code": 200,
"msg": "ok",
"data": "hello"
}