Spring MVC,JSON,长度超过 1000 个字符的字符串字段序列化错误
Spring MVC, JSON, wrong serialization of string fields, that are longer than 1000 characters
我尝试通过注释@ResponseBody 将实体列表作为 JSON 数据从服务器发送到客户端。问题是长度超过 1000 的文本字段序列化不正确。在这种情况下,字符串替换为空符号“\u0000”序列。
我配置 JSON 映射器:
@Configuration
@EnableWebMvc
@EnableScheduling
@ComponentScan({"configs", "controllers", "services", "models"})
public class WebConfig
{
@Bean RequestMappingHandlerAdapter requestMappingHandlerAdapter()
{
RequestMappingHandlerAdapter reqMapHAdapter=new RequestMappingHandlerAdapter();
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.indentOutput(true);
MappingJackson2HttpMessageConverter httpMsgConv=new MappingJackson2HttpMessageConverter(builder.build());
httpMsgConv.setPrettyPrint(true);
ArrayList<MediaType> mediaTypes=new ArrayList<>();
mediaTypes.add(new MediaType("application", "json", StandardCharsets.UTF_8));
httpMsgConv.setSupportedMediaTypes(mediaTypes);
ArrayList<HttpMessageConverter<?>> msgConvs=new ArrayList<>();
msgConvs.add(httpMsgConv);
reqMapHAdapter.setMessageConverters(msgConvs);
return reqMapHAdapter;
}
...
}
控制器的方法:
@Controller
public class MyController
{
@RequestMapping(value={GET_MESSAGES_URL}, method=RequestMethod.GET)
@ResponseBody List<MessageViewItem> getMessages()
{
// getting List<MesssageViewItem>
List<MessageViewItem> messages=...;
return messages;
}
}
MessageViewItem class:
public class MessageViewItem
{
private String text,
localizedSendingDate;
private UserShortViewItem author;
private Long messageId;
// default constructor, getters and setters ...
}
和结果,如果 text.length()<=1000:
[ {
"text" : "123",
"localizedSendingDate" : "1 day ago",
"author" : {
"viewName" : "John Doe",
"imageUrl" : "/test_web_spring/images/usersImages/0/0/4.jpg",
"id" : 940
},
"messageId" : 3540
} ]
如果text.length()>1000(我从消息中删除了大部分“\u0000”):
[ {
"text" : " : \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000
\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
"localizedSendingDate" : "3 hour ago",
"author" : {
"viewName" : "John Doe",
"imageUrl" : "/test_web_spring/images/usersImages/0/0/4.jpg",
"id" : 940
},
"messageId" : 3812
} ]
尽管如此,手动调用 ObjectMapper.writeValueAsString 会按预期工作并正常序列化超过 1000 个字符的文本字段。
有什么想法,如何解决这个问题?
添加:测试控制器的方法:
@RequestMapping(value={"/testJsonConv"}, method=RequestMethod.GET)
@ResponseBody MessageViewItem testJsonConv()
{
MessageViewItem msgViewItem=new MessageViewItem();
msgViewItem.setText("Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo");
return msgViewItem;
}
结果(切掉大部分“\u0000”):
{
"text" : " : \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
"localizedSendingDate" : null,
"author" : null,
"messageId" : null
}
我看到两个可能的解决方案:
使用显式转换为JSON,像这样:
@控制器
public class 我的控制器
{
@Autowired ObjectMapper 映射器;
// manually convert you'r data to JSON string, and send as text
@RequestMapping(value={GET_MESSAGES_URL},
method=RequestMethod.GET, produces=MediaType.TEXT_PLAIN) throws ...
@ResponseBody String getMessages()
{
// getting List<MesssageViewItem>
List<MessageViewItem> messages=...;
return mapper.writeValueAsString(messages);
}
}
不要忘记为文本媒体类型添加消息转换器:
@Configuration
@EnableScheduling
@EnableAsync
@ComponentScan({"configs", "models"})
public class WebConfig
{
@Bean RequestMappingHandlerAdapter requestMappingHandlerAdapter()
{
RequestMappingHandlerAdapter reqMapHAdapter=new RequestMappingHandlerAdapter();
ArrayList<HttpMessageConverter<?>> msgConvs=new ArrayList<>();
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
stringConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN));
msgConvs.add(stringConverter);
reqMapHAdapter.setMessageConverters(msgConvs);
return reqMapHAdapter;
}
...
}
- 我的项目更新依赖关系后问题消失了。我将 spring 更新到 4.2.4 和(可能是最重要的)- jackson,从 codehaus 到最后一个 fasterxml 版本。
这是一个 post,我想将其标记为答案。作者建议更新 jackson 库,它对我有帮助。但,
不幸的是,我找不到这个 post。
我尝试通过注释@ResponseBody 将实体列表作为 JSON 数据从服务器发送到客户端。问题是长度超过 1000 的文本字段序列化不正确。在这种情况下,字符串替换为空符号“\u0000”序列。
我配置 JSON 映射器:
@Configuration
@EnableWebMvc
@EnableScheduling
@ComponentScan({"configs", "controllers", "services", "models"})
public class WebConfig
{
@Bean RequestMappingHandlerAdapter requestMappingHandlerAdapter()
{
RequestMappingHandlerAdapter reqMapHAdapter=new RequestMappingHandlerAdapter();
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.indentOutput(true);
MappingJackson2HttpMessageConverter httpMsgConv=new MappingJackson2HttpMessageConverter(builder.build());
httpMsgConv.setPrettyPrint(true);
ArrayList<MediaType> mediaTypes=new ArrayList<>();
mediaTypes.add(new MediaType("application", "json", StandardCharsets.UTF_8));
httpMsgConv.setSupportedMediaTypes(mediaTypes);
ArrayList<HttpMessageConverter<?>> msgConvs=new ArrayList<>();
msgConvs.add(httpMsgConv);
reqMapHAdapter.setMessageConverters(msgConvs);
return reqMapHAdapter;
}
...
}
控制器的方法:
@Controller
public class MyController
{
@RequestMapping(value={GET_MESSAGES_URL}, method=RequestMethod.GET)
@ResponseBody List<MessageViewItem> getMessages()
{
// getting List<MesssageViewItem>
List<MessageViewItem> messages=...;
return messages;
}
}
MessageViewItem class:
public class MessageViewItem
{
private String text,
localizedSendingDate;
private UserShortViewItem author;
private Long messageId;
// default constructor, getters and setters ...
}
和结果,如果 text.length()<=1000:
[ {
"text" : "123",
"localizedSendingDate" : "1 day ago",
"author" : {
"viewName" : "John Doe",
"imageUrl" : "/test_web_spring/images/usersImages/0/0/4.jpg",
"id" : 940
},
"messageId" : 3540
} ]
如果text.length()>1000(我从消息中删除了大部分“\u0000”):
[ {
"text" : " : \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000
\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
"localizedSendingDate" : "3 hour ago",
"author" : {
"viewName" : "John Doe",
"imageUrl" : "/test_web_spring/images/usersImages/0/0/4.jpg",
"id" : 940
},
"messageId" : 3812
} ]
尽管如此,手动调用 ObjectMapper.writeValueAsString 会按预期工作并正常序列化超过 1000 个字符的文本字段。
有什么想法,如何解决这个问题?
添加:测试控制器的方法:
@RequestMapping(value={"/testJsonConv"}, method=RequestMethod.GET)
@ResponseBody MessageViewItem testJsonConv()
{
MessageViewItem msgViewItem=new MessageViewItem();
msgViewItem.setText("Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt, explicabo. nemo enim ipsam voluptatem, quia voluptas sit, aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos, qui ratione voluptatem sequi nesciunt, neque porro quisquam est, qui dolorem ipsum, quia dolor sit, amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt, ut labore et dolore magnam aliquam quaerat voluptatem. ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? quis autem vel eum iure reprehenderit, qui in ea voluptate velit esse, quam nihil molestiae consequatur, vel illum, qui dolorem eum fugiat, quo voluptas nulla pariatur?Sed ut perspiciatis, unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam eaque ipsa, quae ab illo");
return msgViewItem;
}
结果(切掉大部分“\u0000”):
{
"text" : " : \u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000",
"localizedSendingDate" : null,
"author" : null,
"messageId" : null
}
我看到两个可能的解决方案:
使用显式转换为JSON,像这样:
@控制器 public class 我的控制器 { @Autowired ObjectMapper 映射器;
// manually convert you'r data to JSON string, and send as text @RequestMapping(value={GET_MESSAGES_URL}, method=RequestMethod.GET, produces=MediaType.TEXT_PLAIN) throws ... @ResponseBody String getMessages() { // getting List<MesssageViewItem> List<MessageViewItem> messages=...; return mapper.writeValueAsString(messages); }
}
不要忘记为文本媒体类型添加消息转换器:
@Configuration
@EnableScheduling
@EnableAsync
@ComponentScan({"configs", "models"})
public class WebConfig
{
@Bean RequestMappingHandlerAdapter requestMappingHandlerAdapter()
{
RequestMappingHandlerAdapter reqMapHAdapter=new RequestMappingHandlerAdapter();
ArrayList<HttpMessageConverter<?>> msgConvs=new ArrayList<>();
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
stringConverter.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN));
msgConvs.add(stringConverter);
reqMapHAdapter.setMessageConverters(msgConvs);
return reqMapHAdapter;
}
...
}
- 我的项目更新依赖关系后问题消失了。我将 spring 更新到 4.2.4 和(可能是最重要的)- jackson,从 codehaus 到最后一个 fasterxml 版本。
这是一个 post,我想将其标记为答案。作者建议更新 jackson 库,它对我有帮助。但, 不幸的是,我找不到这个 post。