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)

相关推荐
救救孩子把15 分钟前
深入理解 Java 对象的内存布局
java
落落落sss17 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
万物皆字节23 分钟前
maven指定模块快速打包idea插件Quick Maven Package
java
夜雨翦春韭30 分钟前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法
我行我素,向往自由36 分钟前
速成java记录(上)
java·速成
一直学习永不止步42 分钟前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序
邵泽明43 分钟前
面试知识储备-多线程
java·面试·职场和发展
Yvemil71 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
程序员是干活的1 小时前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript