Spring boot 2.0 升级到 3.3.1 的相关问题 (四)

文章目录

    • Jackson的配置问题
      • 问题介绍
        • [`MappingJackson2HttpMessageConverter` 没有默认编码的问题](#MappingJackson2HttpMessageConverter 没有默认编码的问题)
        • [自定义`com.fasterxml.jackson.databind.Module` bean 不生效的问题](#自定义com.fasterxml.jackson.databind.Module bean 不生效的问题)
      • 问题解决
      • 相关资料
        • [`MappingJackson2HttpMessageConverter` 转换器构造流程](#MappingJackson2HttpMessageConverter 转换器构造流程)
        • 其他

#Spring boot 2.0 升级到 3.3.1 的相关问题 (四)

Jackson的配置问题

问题介绍

MappingJackson2HttpMessageConverter 没有默认编码的问题

在Spring Boot 3.3.1 自定配置创建的MappingJackson2HttpMessageConverter 默认是没有指定字符串编码,因此在实际的使用中会自动使用ISO8859-1的编码。

StringHttpMessageConverter 默认编码为ISO8859-1,这个也需要修改。

自定义com.fasterxml.jackson.databind.Module bean 不生效的问题

由于Spring 自动配置的MappingJackson2HttpMessageConverter 创建时并不会使用配置的com.fasterxml.jackson.databind.Module ,因此会导致原型2.0版本通过该方式配置的JSON自定义序列化和反序列化无效。

问题解决

方案1

增加一个配置类实现WebMvcConfigurer 接口,并实现configureMessageConverters 或者extendMessageConverters 方法。这个两个方法都会将当前的系统中的所有MessageConverters传入。区别在于extendMessageConverters是做后置加工的,也就是到执行它的时候,系统内的MessageConverters已经是被前置处理过的(前置操作包括合并、排序等),而configureMessageConverters是没有被前置处理,甚至是部分的MessageConverters

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 自定义的Mvc配置,用于配置转换器
 */
@Configuration
public class CustomWebMvcConverterConfigurer implements WebMvcConfigurer {

    @Autowired
    private com.fasterxml.jackson.databind.Module customJackSonModule;


    /**
     * 扩展消息转换器列表,以支持自定义的字符集和Jackson模块。
     * 此方法遍历给定的消息转换器列表,并对特定类型的转换器应用自定义配置。
     * 具体来说,它将字符串转换器的默认字符集设置为UTF-8,并为Jackson转换器注册一个自定义的Jackson模块。
     *
     * @param converters 消息转换器的列表,这里我们将遍历这个列表并对特定的转换器进行配置。
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 遍历给定的消息转换器列表
        for(HttpMessageConverter<?> converter : converters) {
            // 如果当前转换器是字符串转换器,则将其默认字符集设置为UTF-8
            if(converter instanceof StringHttpMessageConverter stringHttpMessageConverter) {
                stringHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
                continue;
            }
            // 如果当前转换器是Jackson 2转换器,则将其默认字符集设置为UTF-8,并注册自定义的Jackson模块
            if(converter instanceof MappingJackson2HttpMessageConverter jackson2HttpMessageConverter) {
                jackson2HttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
                ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();
                // 注册自定义的Jackson模块,以支持额外的序列化和反序列化需求
                objectMapper.registerModule(customJackSonModule);
            }
        }
    }

}
方案2

直接在创建一个MappingJackson2HttpMessageConverter Bean。

java 复制代码
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.nio.charset.StandardCharsets;


@Configuration
public class JacksonConfiguration {

    @Autowired
    private com.fasterxml.jackson.databind.Module customJackSonModule;
    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        // 注册自定义Module
        objectMapper.registerModule(customJackSonModule);
        converter.setObjectMapper(objectMapper);
        //默认字符集设置为UTF-8
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        return converter;
    }
}   }
}
方案3 (不可行)

自定义Jackson2ObjectMapperBuilderCustomizer ,用于配置Jackson2ObjectMapperBuilder

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

/**
 * 配置Jackson2ObjectMapperBuilderCustomizer 
 */
@Configuration
public class JacksonConfiguration {

    @Autowired
    private com.fasterxml.jackson.databind.Module customJackSonModule;
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperBuilderCustomizer() {
        return new Jackson2ObjectMapperBuilderCustomizer() {
            @Override
            public void customize(Jackson2ObjectMapperBuilder builder) {
                // 注册自定义的 Module
                builder.modulesToInstall(customJackSonModule);
            }
        };
    }
}

该方案不可行的原因是Spring Boot自动配置的MappingJackson2HttpMessageConverter 使用的ObjectMapper就没使用Jackson2ObjectMapperBuilder 的Bean去创建的,而是每次都重新创建一个Jackson2ObjectMapperBuilder的创建的。 这个应该是给未来版本来解决的,详情可以看org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration 这个类。

相关资料

MappingJackson2HttpMessageConverter 转换器构造流程

几个构造流程:

1、org.springframework.boot.autoconfigure.BackgroundPreinitializerorg.springframework.boot.autoconfigure.BackgroundPreinitializer.MessageConverterInitializer 初始化AllEncompassingFormHttpMessageConverter 消息转换器。在这个消息转换器中默认会初始化一堆消息转换器,其中就包含MappingJackson2HttpMessageConverter的无参构造方法。

2、org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration#formContentFilter 方法中创建了一个OrderedFormContentFilter 的Filter,这个Filter中默认会创建一个AllEncompassingFormHttpMessageConverter 消息转换器。在这个消息转换器中默认会初始化一堆消息转换器,其中就包含MappingJackson2HttpMessageConverter的无参构造方法。

AllEncompassingFormHttpMessageConverter 只处理Form 表单请求(请求头为application/x-www-form-urlencoded)的转换。

3、org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration.MappingJackson2HttpMessageConverterConfiguration#mappingJackson2HttpMessageConverter ,使用指定的ObjectMapper创建了一个MappingJackson2HttpMessageConverter

4、org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerAdapter -> org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getMessageConverters ->
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#addDefaultHttpMessageConverters 使用默认的Jackson2ObjectMapperBuilder的配置创建一个MappingJackson2HttpMessageConverter

5、org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration#messageConverters

其他

默认的Jackson2ObjectMapperBuilderCustomizer 的实现
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration.Jackson2ObjectMapperBuilderCustomizerConfiguration.StandardJackson2ObjectMapperBuilderCustomizer

HttpMessageConverterwrite 方法调用点
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, org.springframework.core.MethodParameter, org.springframework.http.server.ServletServerHttpRequest, org.springframework.http.server.ServletServerHttpResponse)

相关推荐
程序员爱钓鱼5 分钟前
Go语言实战案例-使用ORM框架 GORM 入门
后端
M1A16 分钟前
TCP协议详解:为什么它是互联网的基石?
后端·网络协议·tcp/ip
瓦特what?7 分钟前
关于C++的#include的超超超详细讲解
java·开发语言·数据结构·c++·算法·信息可视化·数据挖掘
一枚小小程序员哈15 分钟前
基于微信小程序的家教服务平台的设计与实现/基于asp.net/c#的家教服务平台/基于asp.net/c#的家教管理系统
后端·c#·asp.net
楽码43 分钟前
自动修复GoVet:语言实现对比
后端·算法·编程语言
石榴树下1 小时前
00. 马里奥的 OAuth 2 和 OIDC 历险记
后端
是乐谷1 小时前
阿里云杭州 AI 产品法务岗位信息分享(2025 年 8 月)
java·人工智能·阿里云·面试·职场和发展·机器人·云计算
uhakadotcom1 小时前
开源:subdomainpy快速高效的 Python 子域名检测工具
前端·后端·面试
似水流年流不尽思念1 小时前
容器化技术了解吗?主要解决什么问题?原理是什么?
后端
Java水解1 小时前
Java中的四种引用类型详解:强引用、软引用、弱引用和虚引用
java·后端