当前位置: 首页 > news >正文

Spring Boot 自定义 HttpMessageConverter 导致 Swagger 文档无法访问的解决方案

问题背景

在 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 的预期格式。

问题原因

  1. 覆盖默认转换器
    Spring Boot 默认会注册 MappingJackson2HttpMessageConverter,用于 JSON 序列化。当我们手动添加自定义转换器并放在首位(converters.add(0, ...)),会导致 Swagger 使用的默认转换器被跳过。

  2. 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) {
        @Override
        public 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

相关文章:

  • 计算机网络:(三)计算机网络体系结构(附带图谱表格更好对比理解)
  • 解锁智能协作:蓝耘平台如何打破应用壁垒,实现无缝联动
  • 深入解析SSL/TLS证书:构建现代网络安全的密码学基石1.1 TLS 1.3握手流程优化
  • [数据结构] 动态顺序表应用
  • CSS+JS 堆叠图片动态交互切换
  • Opencv计算机视觉编程攻略-第三节 图像颜色处理
  • 【docker】docker-compose安装RabbitMQ
  • 08-项目中不可控的任务如何安排和验收
  • WPF(Windows Presentation Foundation)与 C# 基础知识详解
  • 【Linux知识】RPM软件包安装命令行详细说明
  • 代码随想录Day23
  • [ComfyUI] AlekPetNodes 插件详解:节点与模型管理
  • 2小样本学习(Few-Shot)之相似度
  • 000-JMeter简介
  • JVM之类的加载过程
  • 硬件基础--02_前序知识
  • 【C++】STL性能优化实战
  • 硬件基础(3):三极管(4):关于三极管的压降
  • 诡异的服务重启原因探索
  • 【AWS】使用CloudFront S3 Lambda打造丝滑低延迟Web体验
  • 2025年上海科技节开幕,人形机器人首次登上科学红毯
  • 刘小涛任江苏省委副书记
  • 马上评|训斥打骂女儿致死,无暴力应是“管教”底线
  • 加拿大新政府宣誓就职
  • “11+2”复式票,宝山购彩者领走大乐透1170万头奖
  • 秦洪看盘|交易新逻辑,银行股成A股稳定器