使用HttpMessageConverter实现HTTP的序列化和反序列化

本文介绍了对象的序列化/反序列化,着重讲解了http序列化和反序列化。在springmvc/SpringBoot中,Http序列化/反序列化是controller层框架核心功能之一,其核心是HttpMessageConverter。还说明了如何替换@ResponseBody默认的HttpMessageConverter,如用fastjson替代默认的jackson转化方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对象的序列化/反序列化大家应该都比较熟悉:序列化就是将object转化为可以传输的二进制,反序列化就是将二进制转化为程序内部的对象。序列化/反序列化主要体现在程序I/O这个过程中,包括网络I/O和磁盘I/O。

那么什么是http序列化和反序列化呢?

在使用springmvc/SpringBoot时,我们经常会这样写:

@RequestMapping("/test")
@ResponseBodypublic String test(@RequestBody String param) {
    return "param '" + param + "'";
}

@RestController中有@ResponseBody,可以帮我们把User序列化到resp.body中。@RequestBody可以帮我们把req.body的内容转化为User对象。如果是开发Web应用,一般这两个注解对应的就是Json序列化和反序列化的操作。这里实际上已经体现了Http序列化/反序列化这个过程,只不过和普通的对象序列化有些不一样,Http序列化/反序列化的层次更高,属于一种Object2Object之间的转换。

有过Netty使用经验的对这个应该比较了解,Netty中的Decoder和Encoder就有两种基本层次,层次低的一种是Byte <—> Message,二进制与程序内部消息对象之间的转换,就是常见的序列化/反序列化;另外一种是 Message <—> Message,程序内部对象之间的转换,比较高层次的序列化/反序列化。

Http协议的处理过程,TCP字节流 <—> HttpRequest/HttpResponse <—> 内部对象,就涉及这两种序列化。在springmvc中第一步已经由Servlet容器(tomcat等等)帮我们处理了,第二步则主要由框架帮我们处理。上面所说的Http序列化/反序列化就是指的这第二个步骤,它是controller层框架的核心功能之一,有了这个功能,就能大大减少代码量,让controller的逻辑更简洁清晰,就像上面示意的代码那样,方法中只有一行代码。spirngmvc进行第二步操作,也就是Http序列化和反序列化的核心是HttpMessageConverter。

HttpMessageConverter

Http请求响应报文其实都是字符串,当请求报文到java程序会被封装为一个ServletInputStream流,开发人员再读取报文,响应报文则通过ServletOutputStream流,来输出响应报文。

从流中只能读取到原始的字符串报文,同样输出流也是。那么在报文到达SpringMVC / SpringBoot和从SpringMVC / SpringBoot出去,都存在一个字符串到java对象的转化问题。这一过程,在SpringMVC / SpringBoot中,是通过HttpMessageConverter来解决的。HttpMessageConverter接口源码:
在这里插入图片描述
以上面的代码为例子来说明一下:在请求进入test方法前,会根据@RequestBody注解选择对应的HttpMessageConverter实现类来将请求参数解析到param变量中,因为这里的参数是String类型的,所以这里是使用了StringHttpMessageConverter类,它的canRead()方法返回true,然后read()方法会从请求中读出请求参数,绑定到test()方法的param变量中。

同理当执行test方法后,由于返回值标识了@ResponseBody,SpringMVC / SpringBoot将使用StringHttpMessageConverter的write()方法,将结果作为String值写入响应报文,当然,此时canWrite()方法返回true。

借用下图简单描述整个过程:
在这里插入图片描述
在Spring的处理过程中,一次请求报文和一次响应报文,分别被抽象为一个请求消息HttpInputMessage和一个响应消息HttpOutputMessage。处理请求时,由合适的消息转换器将请求报文绑定为方法中的形参对象,在这里同一个对象就有可能出现多种不同的消息形式,如json、xml。同样响应请求也是同样道理。在Spring中,针对不同的消息形式,有不同的HttpMessageConverter实现类来处理各种消息形式,至于各种消息解析实现的不同,则在不同的HttpMessageConverter实现类中。

替换@ResponseBody默认的HttpMessageConverter

1、springboot框架默认的使用jackson进行json转化

public class User {

    private String username;
    private Integer age;
    private Integer phone;
    private String email;

    public User(String username, Integer age) {
    super();
    this.username = username;
    this.age = age;
    }
}
@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/testt")
    @ResponseBody
    public User testt() {
        User user = new User("name", 18);
        return user;
    }
}

浏览器访问/user/testt请求结果如下:
在这里插入图片描述
这就是使用Jackson解析的结果,没有传值的字段默认被解析成了null。现在来改成使用fastjson解析对象,这里就是替换默认的HttpMessageConverter,就是将其改成使用FastJsonHttpMessageConverter来处理Java对象与HttpInputMessage/HttpOutputMessage间的转化。

2、使用fastjson替代默认的jackson转化方式

增加Fastjson的maven依赖

<dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.47</version>
</dependency>

Springboot配置FastJsonHttpMessageConverter有两种方法:

方法一:启动类继承extends WebMvcConfigurerAdapter,然后覆盖方法configureMessageConverters

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.apache.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.util.ArrayList;
import java.util.List;

/** springboot以fastjon方式转化json数据 */
@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter {
    private static Logger logger = Logger.getLogger(Application.class);

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
        //1.需要定义一个convert转换消息的对象;
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        //2.添加fastJson的配置信息,比如:是否要格式化返回的json数据;
        FastJsonConfig fastJsonConfig = new FastJsonConfig();

	SerializerFeature[] serializerFeatures = new SerializerFeature[]{
                //    输出key是包含双引号
//                SerializerFeature.QuoteFieldNames,
                //    是否输出为null的字段,若为null 则显示该字段
//                SerializerFeature.WriteMapNullValue,
                //    数值字段如果为null,则输出为0
                SerializerFeature.WriteNullNumberAsZero,
                //     List字段如果为null,输出为[],而非null
                SerializerFeature.WriteNullListAsEmpty,
                //    字符类型字段如果为null,输出为"",而非null
                SerializerFeature.WriteNullStringAsEmpty,
                //    Boolean字段如果为null,输出为false,而非null
                SerializerFeature.WriteNullBooleanAsFalse,
                //    Date的日期转换器
                SerializerFeature.WriteDateUseDateFormat,
                //    循环引用
                SerializerFeature.DisableCircularReferenceDetect,
        };

        fastJsonConfig.setSerializerFeatures(serializerFeatures);
        //3处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        //4.在convert中添加配置信息.
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
        //5.将convert添加到converters当中.
        converters.add(fastJsonHttpMessageConverter);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
        logger.info("=====spring boot start success====");
    }
}

方法二:添加配置类来注入Bean:HttpMessageConverters

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;

import java.nio.charset.Charset;

@Configuration
public class HttpMessageConverterConfig {

    //引入Fastjson解析json,不使用默认的jackson
    //必须在pom.xml引入fastjson的jar包,并且版必须大于1.2.10
    @Bean
    public HttpMessageConverters fastJsonHttpMessageConverters() {
        //1、定义一个convert转换消息的对象
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();

        //2、添加fastjson的配置信息
        FastJsonConfig fastJsonConfig = new FastJsonConfig();

        SerializerFeature[] serializerFeatures = new SerializerFeature[]{
                //    输出key是包含双引号
//                SerializerFeature.QuoteFieldNames,
                //    是否输出为null的字段,若为null 则显示该字段
//                SerializerFeature.WriteMapNullValue,
                //    数值字段如果为null,则输出为0
                SerializerFeature.WriteNullNumberAsZero,
                //     List字段如果为null,输出为[],而非null
                SerializerFeature.WriteNullListAsEmpty,
                //    字符类型字段如果为null,输出为"",而非null
                SerializerFeature.WriteNullStringAsEmpty,
                //    Boolean字段如果为null,输出为false,而非null
                SerializerFeature.WriteNullBooleanAsFalse,
                //    Date的日期转换器
                SerializerFeature.WriteDateUseDateFormat,
                //    循环引用
                SerializerFeature.DisableCircularReferenceDetect,
        };

        fastJsonConfig.setSerializerFeatures(serializerFeatures);
        fastJsonConfig.setCharset(Charset.forName("UTF-8"));

        //3、在convert中添加配置信息
        fastConverter.setFastJsonConfig(fastJsonConfig);

        //4、将convert添加到converters中
        HttpMessageConverter<?> converter = fastConverter;

        return new HttpMessageConverters(converter);
    }
}

浏览器发起请求,得到的结果如下:
在这里插入图片描述
未传值的字符串类型的属性被解析为””,未传值的数值类型的属性被解析为0。

参考资料:
1、【Spring】HttpMessageConverter的作用及替换
2、springboot学习(三)——使用HttpMessageConverter进行http序列化和反序列化
3、SpringBoot-扩展FastJsonHttpMessageConverter对返回的json对象进行扩展
4、fastjson SerializerFeature详解

<think>我们参考了引用内容,特别是引用[1]引用[3]中关于SpringBoot全局配置Jackson序列化反序列化的方法。用户希望了解全局配置的方法,因此我们将重点介绍如何通过自定义ObjectMapper@JsonComponent注解来实现全局配置。###解决方案:SpringBoot全局配置Jackson序列化反序列化####一、核心配置方法在SpringBoot中,可以通过以下两种主要方式全局配置Jackson:1.**自定义ObjectMapperBean**在配置类中定义`ObjectMapper`Bean,SpringBoot会自动使用它替换默认的ObjectMapper。```javaimportcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.SerializationFeature;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassJacksonConfig{@BeanpublicObjectMapperobjectMapper(){ObjectMappermapper=newObjectMapper();//配置序列化行为mapper.enable(SerializationFeature.INDENT_OUTPUT);//美化输出mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);//日期序列化为字符串而非时间戳//配置反序列化行为mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);//忽略未知字段//更多配置...returnmapper;}}```2.**使用`@JsonComponent`自定义序列化/反序列化器**通过`@JsonComponent`注解注册自定义的序列化器或反序列化器,它们会自动被注册到Jackson中[^1]。```javaimportcom.fasterxml.jackson.core.JsonGenerator;importcom.fasterxml.jackson.core.JsonParser;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.*;importorg.springframework.boot.jackson.JsonComponent;@JsonComponent//自动注册publicclassCustomJsonComponent{//自定义序列化器(示例:将Long类型序列化为字符串)publicstaticclassLongSerializerextendsJsonSerializer<Long>{@Overridepublicvoidserialize(Longvalue,JsonGeneratorgen,SerializerProviderserializers)throwsIOException{gen.writeString(value.toString());//将Long转为字符串输出}}//自定义反序列化器(示例:将字符串反序列化为Long)publicstaticclassLongDeserializerextendsJsonDeserializer<Long>{@OverridepublicLongdeserialize(JsonParserp,DeserializationContextctxt)throwsIOException{returnLong.parseLong(p.getText());}}}```####二、常用配置项详解|配置类型|功能|示例代码||----------|------|----------||**序列化配置**|控制Java对象转JSON的行为|`mapper.enable(SerializationFeature.INDENT_OUTPUT)`||**反序列化配置**|控制JSON转Java对象的行为|`mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false)`||**日期格式**|统一设置日期格式|`mapper.setDateFormat(newSimpleDateFormat("yyyy-MM-ddHH:mm:ss"))`||**空值处理**|控制null值的序列化行为|`mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)`|####三、高级场景:注册模块对于复杂数据类型(如Java8日期时间),可通过注册模块实现:```java@BeanpublicObjectMapperobjectMapper(){ObjectMappermapper=newObjectMapper();//注册Java8日期时间模块mapper.registerModule(newJavaTimeModule());//配置日期格式mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);returnmapper;}```####四、配置生效原理SpringBoot通过`JacksonAutoConfiguration`自动配置Jackson。当检测到自定义的`ObjectMapper`Bean时,会优先使用它[^2]。同时,`@JsonComponent`注解的类会被自动扫描并注册到Jackson中[^1]。####五、验证配置是否生效1.**单元测试验证**在测试中注入`ObjectMapper`并检查其行为:```java@AutowiredprivateObjectMapperobjectMapper;@TestvoidtestLongSerialization()throwsJsonProcessingException{Stringjson=objectMapper.writeValueAsString(1000L);Assertions.assertEquals("\"1000\"",json);//验证Long被序列化为字符串}```2.**查看API返回结果**直接调用配置后的接口,观察JSON响应格式。####六、注意事项1.**配置冲突**如果同时存在多个配置源(如`application.yml`自定义ObjectMapper),SpringBoot的优先级为:**自定义Bean>配置文件**。2.**与其他JSON库共存**如引用[2]所述,若同时存在JacksonFastJson,需确保Jackson的`HttpMessageConverter`优先级更高(默认如此)。####七、完整配置示例```java@ConfigurationpublicclassJacksonConfig{@BeanpublicObjectMapperobjectMapper(){ObjectMappermapper=newObjectMapper();//基本配置mapper.enable(SerializationFeature.INDENT_OUTPUT);mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);//注册模块mapper.registerModule(newJavaTimeModule());mapper.registerModule(newSimpleModule().addSerializer(Long.class,newLongSerializer()).addDeserializer(Long.class,newLongDeserializer()));returnmapper;}}```>通过以上方法,可全面控制SpringBoot中Jackson的全局序列化反序列化行为。实际开发中建议根据项目需求选择合适配置方式[^1][^3]。§§相关问题§§1.如何在SpringBoot中配置Jackson的日期格式?2.如何忽略Jackson反序列化时的未知字段?3.如何使用Jackson自定义枚举类型的序列化行为?</think>### Spring Boot 全局配置 Jackson 序列化反序列化方法 在 Spring Boot 中,Jackson 是默认的 JSON 处理器,通过全局配置可以统一管理其序列化(Java对象→JSON)反序列化(JSON→Java对象)行为。以下是三种核心配置方式: --- #### 一、自定义 ObjectMapper Bean(推荐) 在配置类中定义 `ObjectMapper` Bean,Spring Boot 会自动将其应用于所有 Jackson 操作: ```java import com.fasterxml.jackson.databind.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); // 序列化配置 mapper.enable(SerializationFeature.INDENT_OUTPUT); // 美化输出 mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // 日期序列化为字符串而非时间戳 // 反序列化配置 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 忽略未知字段 mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); // 空字符串转为null // 空值处理 mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 序列化时忽略null字段 // 注册模块(如Java 8时间模块) mapper.registerModule(new JavaTimeModule()); return mapper; } } ``` **生效原理**:Spring Boot 的 `JacksonAutoConfiguration` 会自动检测自定义的 ObjectMapper Bean 并替换默认实现[^3]。 --- #### 二、通过配置文件配置(application.yml) 在 `application.yml` 中直接设置 Jackson 属性: ```yaml spring: jackson: date-format: yyyy-MM-dd HH:mm:ss # 日期格式 time-zone: GMT+8 # 时区 serialization: write-dates-as-timestamps: false # 禁用时间戳 indent-output: true # 美化输出 deserialization: fail-on-unknown-properties: false # 忽略未知字段 default-property-inclusion: non_null # 全局忽略null字段 ``` > **注意**:配置文件优先级低于自定义 ObjectMapper Bean,两者共存时以 Bean 配置为准[^3]。 --- #### 三、使用 `@JsonComponent` 自定义序列化/反序列化器 对特定类型实现精细化控制: ```java import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; import org.springframework.boot.jackson.*; @JsonComponent // 自动注册到Jackson public class CustomSerializers { // 自定义序列化器(示例:将Long转为字符串) public static class LongSerializer extends JsonSerializer<Long> { @Override public void serialize(Long value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeString(value.toString()); // 输出为字符串 } } // 自定义反序列化器(示例:空字符串转null) public static class StringDeserializer extends JsonDeserializer<String> { @Override public String deserialize(JsonParser p, DeserializationContext ctx) throws IOException { String value = p.getText(); return value.isEmpty() ? null : value; // 空字符串转null } } } ``` --- ### 四、关键配置项说明 | **配置类型** | **常用选项** | **作用** | |---------------------|-----------------------------------------------------------------------------|---------------------------------------| | **序列化配置** | `SerializationFeature.INDENT_OUTPUT` | 美化JSON输出 | | | `SerializationFeature.WRITE_DATES_AS_TIMESTAMPS` | 日期是否输出为时间戳 | | **反序列化配置** | `DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES` | 遇到未知字段是否报错 | | | `DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT` | 空字符串是否转为null | | **空值处理** | `JsonInclude.Include.NON_NULL` | 序列化时忽略null字段 | | | `JsonInclude.Include.NON_EMPTY` | 忽略空值或空集合 | | **日期处理** | `.registerModule(new JavaTimeModule())` | 支持Java 8日期类型 | | | `.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"))` | 自定义日期格式 | --- ### 五、配置验证方法 1. **单元测试验证** ```java @SpringBootTest class JacksonTest { @Autowired ObjectMapper objectMapper; // 注入配置后的ObjectMapper @Test void testConfig() throws JsonProcessingException { TestObj obj = new TestObj(null, ""); String json = objectMapper.writeValueAsString(obj); // 应输出: {} (忽略null空字符串) } static class TestObj { private String name; private String address; // 构造方法省略... } } ``` 2. **查看API输出** 直接调用Controller接口,观察返回的JSON格式是否符合预期。 --- ### 六、常见问题解决 1. **配置不生效** - 检查是否有多处配置冲突(如同时存在Bean配置配置文件) - 确保没有手动创建新的 `ObjectMapper` 实例 2. **日期处理异常** ```java // 必须注册JavaTimeModule mapper.registerModule(new JavaTimeModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); ``` 3. **枚举反序列化** ```java // 允许枚举反序列化时忽略大小写 mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE); ``` > 通过合理组合这些配置,可实现全局统一的JSON处理策略,确保系统行为一致性[^1][^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值