问题背景
在 Spring Boot 项目中,我们经常需要自定义 HttpMessageConverter
来处理 JSON 序列化,比如将 Long
类型转换为 String
以避免前端 JavaScript 的精度丢失问题。然而,当我们直接覆盖默认的 MappingJackson2HttpMessageConverter
时,可能会导致 Swagger 文档无法正常访问,返回空白页面或 JSON 解析错误。
问题复现
以下是一个典型的自定义 HttpMessageConverter
配置:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();ObjectMapper objectMapper = new ObjectMapper();SimpleModule simpleModule = new SimpleModule();simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);simpleModule.addSerializer(Long.class, ToStringSerializer.instance);simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);objectMapper.registerModule(simpleModule);objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);jackson2HttpMessageConverter.setObjectMapper(objectMapper);converters.add(0, jackson2HttpMessageConverter); // 添加到首位
}
问题现象:
-
访问
http://localhost:8080/swagger-ui.html
时,页面无法加载或显示异常。 -
直接访问
http://localhost:8080/v3/api-docs/default
时,返回的 JSON 数据可能不符合 Swagger 的预期格式。
问题原因
-
覆盖默认转换器
Spring Boot 默认会注册MappingJackson2HttpMessageConverter
,用于 JSON 序列化。当我们手动添加自定义转换器并放在首位(converters.add(0, ...)
),会导致 Swagger 使用的默认转换器被跳过。 -
ObjectMapper 配置冲突
Swagger 依赖特定的ObjectMapper
配置来生成 API 文档。如果我们修改了ObjectMapper
(如Long
转String
),可能会破坏 Swagger 的 JSON 结构,导致文档无法正确渲染。
解决方案
方案 1:仅修改现有的 Jackson 转换器(推荐)
避免覆盖默认转换器,而是找到已存在的 MappingJackson2HttpMessageConverter
并修改其 ObjectMapper
:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {for (HttpMessageConverter<?> converter : converters) {if (converter instanceof MappingJackson2HttpMessageConverter) {ObjectMapper objectMapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();configureObjectMapper(objectMapper);return;}}// 如果没找到,再添加新的转换器addNewJacksonConverter(converters);
}private void configureObjectMapper(ObjectMapper objectMapper) {SimpleModule module = new SimpleModule();module.addSerializer(BigInteger.class, ToStringSerializer.instance);module.addSerializer(Long.class, ToStringSerializer.instance);module.addSerializer(Long.TYPE, ToStringSerializer.instance);objectMapper.registerModule(module);objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}private void addNewJacksonConverter(List<HttpMessageConverter<?>> converters) {MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();ObjectMapper objectMapper = new ObjectMapper();configureObjectMapper(objectMapper);converter.setObjectMapper(objectMapper);converters.add(converter);
}
方案 2:动态判断请求路径,Swagger 请求走默认转换器
如果必须添加新的 HttpMessageConverter
,可以动态判断请求路径,让 Swagger 请求仍然使用默认转换器:
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {ObjectMapper customObjectMapper = new ObjectMapper();SimpleModule module = new SimpleModule();module.addSerializer(BigInteger.class, ToStringSerializer.instance);module.addSerializer(Long.class, ToStringSerializer.instance);module.addSerializer(Long.TYPE, ToStringSerializer.instance);customObjectMapper.registerModule(module);customObjectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);MappingJackson2HttpMessageConverter customConverter = new MappingJackson2HttpMessageConverter(customObjectMapper) {@Overridepublic boolean canWrite(Class<?> clazz, MediaType mediaType) {// 如果是 Swagger 请求,则不使用自定义转换器ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attrs != null) {String path = attrs.getRequest().getRequestURI();if (path.startsWith("/v3/api-docs") || path.startsWith("/swagger-ui")) {return false; // 让默认转换器处理}}return super.canWrite(clazz, mediaType);}};converters.add(0, customConverter);
}
方案对比
方案 | 优点 | 缺点 |
---|---|---|
修改现有转换器 | 兼容性最好,不影响 Swagger | 需要确保默认转换器存在 |
动态路径判断 | 灵活控制不同请求的转换逻辑 | 需要依赖 RequestContextHolder |
总结
-
推荐使用方案 1(修改现有转换器),因为它不会破坏 Spring Boot 的默认行为,兼容性更好。
-
如果必须新增转换器,可以使用 方案 2(动态路径判断),确保 Swagger 仍然能正常工作。
-
最终目标是 让 Swagger 使用默认的
ObjectMapper
,而业务接口使用自定义的 JSON 序列化规则。
这样,既能解决前端 Long
精度问题,又能保证 Swagger 文档正常访问! 🚀
📌 欢迎在评论区讨论你的解决方案!
🔗 相关技术:Spring Boot、Swagger、HttpMessageConverter、ObjectMapper