Spring MVC(非Spring Boot)环境下Jackson转换器的正确配置:支持无空值JSON、合法字符串JSON与纯文本响应
解决方案:让消息转换器各司其职
核心问题出在StringHttpMessageConverter和MappingJackson2HttpMessageConverter的职责重叠——当你把StringHttpMessageConverter放在前面时,它会处理所有String类型的返回值,不管这个返回值应该是纯文本还是JSON格式的字符串。我们需要给每个转换器明确划分处理范围,让它们只负责对应的MediaType。
步骤1:配置专属的字符串转换器(仅处理纯文本)
创建一个只支持text/plain类型的StringHttpMessageConverter,这样它不会抢占JSON格式的字符串处理:
@Bean public StringHttpMessageConverter stringHttpMessageConverter() { StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8); // 仅让该转换器处理text/plain类型的响应 converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_PLAIN)); return converter; }
步骤2:保持JSON转换器的配置(去除null字段)
你的原有JSON转换器配置可以保留,但建议加上UTF-8的MediaType以避免编码问题:
@Bean public MappingJackson2HttpMessageConverter jsonConverter() { List<MediaType> supportedMediaTypes = new ArrayList<>(); supportedMediaTypes.add(MediaType.APPLICATION_JSON); supportedMediaTypes.add(new MediaType("application", "json", StandardCharsets.UTF_8)); // 支持UTF-8编码的JSON Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.serializationInclusion(JsonInclude.Include.NON_NULL); builder.timeZone(TimeZone.getTimeZone(timeZone)); MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(builder.build()); jsonConverter.setSupportedMediaTypes(supportedMediaTypes); return jsonConverter; }
步骤3:按顺序注册转换器
在configureMessageConverters中按顺序添加两个转换器——先纯文本转换器,再JSON转换器:
@Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { converters.add(stringHttpMessageConverter()); converters.add(jsonConverter()); }
步骤4:明确端点的响应类型
为了让Spring能正确匹配转换器,建议给每个端点明确指定produces属性:
- 纯文本端点:指定
produces = MediaType.TEXT_PLAIN_VALUE@RequestMapping(value = "/plain-text", produces = MediaType.TEXT_PLAIN_VALUE) @ResponseBody public String getPlainText() { return "Hello Plain Text"; // 直接返回不带引号的纯文本 } - JSON字符串端点:指定
produces = MediaType.APPLICATION_JSON_VALUE@RequestMapping(value = "/json-string", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public String getJsonString() { return "Hello JSON String"; // 会被Jackson序列化为带引号的JSON:"Hello JSON String" } - POJO转JSON端点:同样指定
produces = MediaType.APPLICATION_JSON_VALUE@RequestMapping(value = "/pojo-json", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public User getUser() { User user = new User(); user.setName("Alice"); user.setAge(null); // null字段会被自动移除 return user; }
原理说明
Spring在处理响应时,会根据端点的produces属性和返回值类型,从注册的转换器中选择最匹配的那个:
- 当响应类型是
text/plain时,StringHttpMessageConverter会处理,直接返回原始字符串; - 当响应类型是
application/json时,不管返回值是POJO还是String,MappingJackson2HttpMessageConverter都会处理:POJO会被序列化为去除null字段的JSON,String会被序列化为带双引号的合法JSON字符串。
内容的提问来源于stack exchange,提问作者Pieter
相关产品推荐
相关产品推荐

