对后端返回的日期属性进行格式化(扩展 Spring MVC 的消息转换器)

格式化之前                                                  格式化之后:

解决方式

方式一

在属性中加上注解,对日期进行格式化

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    //@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

方式二

在WebMvcConfiguration 中扩展Spring MVC的消息转换器,统一对日期类型进行格式化处理

扩展 Spring MVC 的消息转换器

    /**
     * 扩展Spring MVC框架的消息转换器
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //创建一个消息转换器对象
         MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        //需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
        converter.setObjectMapper(new JacksonObjectMapper());
        //将自己的消息转换器加入容器中(因为converters拥有自带的消息转换器,所以设置索引为0可以优先使用自己的消息转换器)
        converters.add(0,converter);
    }
  • extendMessageConverters 方法: 该方法允许开发者自定义 Spring MVC 的消息转换器。通过重写WebMvcConfigurationSupport中的这个方法,可以添加自定义的消息转换器。
  • @Override: 注解表示这个方法重写了父类中的同名方法,这里是WebMvcConfigurationSupportextendMessageConverters 方法。

  • protected void extendMessageConverters(List<HttpMessageConverter<?>> converters): 方法签名,接收一个 List 类型的参数,包含所有当前注册的消息转换器。

  • MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();

    创建一个新的 MappingJackson2HttpMessageConverter 实例。这个转换器用于将 Java 对象转换为 JSON 格式(序列化),以及将 JSON 数据转换为 Java 对象(反序列化)。
  • converter.setObjectMapper(new JacksonObjectMapper());

    设置自定义的对象转换器(ObjectMapper)。JacksonObjectMapper 是一个自定义类,通常是 ObjectMapper 的一个扩展或配置版本。这样做的目的是让转换器使用特定的配置,例如序列化和反序列化的规则、日期格式等。
  • converters.add(0, converter);

    将自定义的消息转换器添加到转换器列表的第一个位置(索引为0)。这意味着在处理请求时,Spring 会优先使用这个自定义的转换器,而不是默认的转换器。确保你的自定义逻辑在系统的默认逻辑之前执行。

 自定义 ObjectMapper(JacksonObjectMapper)对象转换器

package com.sky.json;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    //public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}
  • JacksonObjectMapper: 这个类继承自 ObjectMapper,用于自定义 JSON 的序列化和反序列化规则。

  • 日期时间格式常量:

    • DEFAULT_DATE_FORMAT: 定义了默认日期格式(yyyy-MM-dd)。
    • DEFAULT_DATE_TIME_FORMAT: 定义了默认日期时间格式(yyyy-MM-dd HH:mm)。
    • DEFAULT_TIME_FORMAT: 定义了默认时间格式(HH:mm:ss)。
  • 构造函数:

    • this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false): 配置 Jackson,使其在遇到未知属性时不抛出异常。这有助于增强反序列化的灵活性。
    • this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES): 进一步确保在反序列化时忽略未知属性。
  • SimpleModule: 创建并注册一个模块,指定如何处理 Java 8 日期和时间 API 类型的序列化与反序列化。

    • 使用 addDeserializer() 方法,定义如何将 JSON 中的日期时间字段解析为 Java 对象。
    • 使用 addSerializer() 方法,定义如何将 Java 对象序列化为 JSON。
  • registerModule(simpleModule): 注册自定义的模块,使得 Jackson 能够使用定义的序列化和反序列化器。

CBOR详解

CBOR(Concise Binary Object Representation)是一种二进制数据格式,主要用于数据序列化和反序列化。它是为了提供一种比 JSON 更高效的方式来编码数据,以满足现代应用程序对性能和存储空间的需求。

CBOR 的特点

  1. 紧凑性:

    CBOR 使用二进制格式,通常比文本格式(如 JSON)占用更少的空间。这使得它在网络传输和存储时更加高效。
  2. 高效性:

    由于 CBOR 是二进制格式,解析速度通常比文本格式快,因为它避免了字符串解析所需的额外处理。
  3. 灵活的数据类型:

    CBOR 支持多种数据类型,包括:
    • 布尔值和空值
    • 映射(键值对)
    • 数组
    • 字符串(文本和二进制)
    • 浮点数
    • 整数(正整数和负整数)
  4. 与 JSON 兼容:

    CBOR 能够表示 JSON 所有的数据结构,这使得它在需要与 JSON 互操作时非常方便。
  5. 自描述性:

    CBOR 数据包含类型信息,接收方可以根据这些信息理解数据的结构,减少了解析时的复杂性。
  6. 扩展性:

    CBOR 允许用户定义扩展类型,可以根据特定的需求添加新的数据类型。

CBOR 的结构

CBOR 数据的基本构成是由一系列的标签、类型标识符和具体数据组成。每个数据项都有一个类型标识符,指示数据的类型。例如:

  • 整数: 0 到 23 用单字节表示,超过这个范围则使用多个字节。
  • 浮点数: 支持半精度和单精度浮点数。
  • 字符串: 可以是 UTF-8 编码的文本或二进制数据。
  • 数组和映射: 分别用于表示有序和无序的数据集合。

应用场景

  1. 物联网(IoT): 在带宽有限的环境中,CBOR 的紧凑性能够显著提高数据传输效率。

  2. 网络通信: 特别是在快速响应和低延迟的应用中,CBOR 提供了更好的性能。

  3. 存储系统: 适合用于大规模数据存储,因其占用空间小且读写效率高。

  4. API 和微服务: CBOR 可用于后端服务之间的数据交换,特别是在 JSON 交互频繁的场合。

总结

CBOR 是一种现代、高效的序列化格式,适用于各种需要高性能和低带宽的应用场景。通过其紧凑的二进制表示和灵活的数据结构,CBOR 为开发者提供了处理数据的新工具,尤其是在物联网、网络通信和存储系统等领域。

示例数据

假设我们有一个简单的字典对象,内容如下:

{
  "name": "Alice",
  "age": 30,
  "isStudent": false,
  "courses": ["Math", "Science"],
  "grades": {
    "Math": 90,
    "Science": 85
  }
}

转换为 CBOR

将上述 JSON 数据转换为 CBOR 格式后,它的二进制表示可能类似于以下内容(注意:实际的二进制数据会因实现而异,以下为示意):

A5 67 6E 61 6D 65 61 6C 69 63 18 1E 67 61 67 65 30 1E 69 73 53 74 75 64 65 6E 74 6E 65 02 81 04 67 43 6F 75 72 73 82 64 4D 61 74 68 64 39 6D 61 74 68 64 35 53 63 69 65 6E 63 65 38 35

这里的每一段数据代表了 JSON 中的不同部分,例如名称、年龄、课程等。

使用 CBOR 库

在实际编码和解码过程中,可以使用库来处理 CBOR 数据。在 Python 中,我们可以使用 cbor2 库来实现:

import cbor2

# 原始数据
data = {
    "name": "Alice",
    "age": 30,
    "isStudent": False,
    "courses": ["Math", "Science"],
    "grades": {
        "Math": 90,
        "Science": 85
    }
}

# 编码为 CBOR
cbor_data = cbor2.dumps(data)

# 解码回原始数据
decoded_data = cbor2.loads(cbor_data)

print(decoded_data)  # 输出: {'name': 'Alice', 'age': 30, 'isStudent': False, 'courses': ['Math', 'Science'], 'grades': {'Math': 90, 'Science': 85}}

总结

CBOR 是一种高效的二进制数据格式,适合用于需要快速解析和较小数据占用的场景。通过示例可以看到,如何从 JSON 数据转换为 CBOR,以及如何使用库进行编码和解码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

╰つ゛木槿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值