格式化之前 格式化之后:
解决方式
方式一
在属性中加上注解,对日期进行格式化
@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
: 注解表示这个方法重写了父类中的同名方法,这里是WebMvcConfigurationSupport
的extendMessageConverters
方法。 -
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters)
: 方法签名,接收一个List
类型的参数,包含所有当前注册的消息转换器。 -
创建一个新的MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
MappingJackson2HttpMessageConverter
实例。这个转换器用于将 Java 对象转换为 JSON 格式(序列化),以及将 JSON 数据转换为 Java 对象(反序列化)。 -
设置自定义的对象转换器(converter.setObjectMapper(new JacksonObjectMapper());
ObjectMapper
)。JacksonObjectMapper
是一个自定义类,通常是ObjectMapper
的一个扩展或配置版本。这样做的目的是让转换器使用特定的配置,例如序列化和反序列化的规则、日期格式等。 -
将自定义的消息转换器添加到转换器列表的第一个位置(索引为0)。这意味着在处理请求时,Spring 会优先使用这个自定义的转换器,而不是默认的转换器。确保你的自定义逻辑在系统的默认逻辑之前执行。converters.add(0, converter);
自定义 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 的特点
-
紧凑性:
CBOR 使用二进制格式,通常比文本格式(如 JSON)占用更少的空间。这使得它在网络传输和存储时更加高效。 -
高效性:
由于 CBOR 是二进制格式,解析速度通常比文本格式快,因为它避免了字符串解析所需的额外处理。 -
灵活的数据类型:
CBOR 支持多种数据类型,包括:- 布尔值和空值
- 映射(键值对)
- 数组
- 字符串(文本和二进制)
- 浮点数
- 整数(正整数和负整数)
-
与 JSON 兼容:
CBOR 能够表示 JSON 所有的数据结构,这使得它在需要与 JSON 互操作时非常方便。 -
自描述性:
CBOR 数据包含类型信息,接收方可以根据这些信息理解数据的结构,减少了解析时的复杂性。 -
扩展性:
CBOR 允许用户定义扩展类型,可以根据特定的需求添加新的数据类型。
CBOR 的结构
CBOR 数据的基本构成是由一系列的标签、类型标识符和具体数据组成。每个数据项都有一个类型标识符,指示数据的类型。例如:
- 整数: 0 到 23 用单字节表示,超过这个范围则使用多个字节。
- 浮点数: 支持半精度和单精度浮点数。
- 字符串: 可以是 UTF-8 编码的文本或二进制数据。
- 数组和映射: 分别用于表示有序和无序的数据集合。
应用场景
-
物联网(IoT): 在带宽有限的环境中,CBOR 的紧凑性能够显著提高数据传输效率。
-
网络通信: 特别是在快速响应和低延迟的应用中,CBOR 提供了更好的性能。
-
存储系统: 适合用于大规模数据存储,因其占用空间小且读写效率高。
-
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,以及如何使用库进行编码和解码。