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

发布于:2024-07-22 ⋅ 阅读:(64) ⋅ 点赞:(0)


#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

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。


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

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)


网站公告

今日签到

点亮在社区的每一天
去签到