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)

相关推荐
论迹1 分钟前
【Spring Cloud 微服务】-- 服务拆分原则
java·spring cloud·微服务
汤姆yu5 分钟前
基于springboot的民间救援队救助系统
java·spring boot·后端·救援队
闭着眼睛学算法6 分钟前
【双机位A卷】华为OD笔试之【哈希表】双机位A-采购订单【Py/Java/C++/C/JS/Go六种语言】【欧弟算法】全网注释最详细分类最全的华子OD真题题解
java·华为od·散列表
IT_陈寒17 分钟前
React性能优化实战:这5个Hooks技巧让我的应用快了40%
前端·人工智能·后端
勿忘,瞬间26 分钟前
Maven
java·maven
ruleslol43 分钟前
SpringBoot面试题04-BeanDefinition
spring boot
韩立学长1 小时前
基于Springboot的智慧管网灌溉系统i1agupa7(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·spring boot·后端
一 乐1 小时前
高校教务|教务管理|基于springboot+vue的高校教务管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·教务管理
数字冰雹1 小时前
重塑城市公共安全管理的“智慧之眼”
java·大数据·数据库
August_._1 小时前
【MySQL】触发器、日志、锁机制 深度解析
java·大数据·数据库·人工智能·后端·mysql·青少年编程