格式化之前 格式化之后:
解决方式
方式一
在属性中加上注解,对日期进行格式化
java
@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 的消息转换器
java
/**
* 扩展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
的一个扩展或配置版本。这样做的目的是让转换器使用特定的配置,例如序列化和反序列化的规则、日期格式等。 -
converters.add(0, converter);
将自定义的消息转换器添加到转换器列表的第一个位置(索引为0)。这意味着在处理请求时,Spring 会优先使用这个自定义的转换器,而不是默认的转换器。确保你的自定义逻辑在系统的默认逻辑之前执行。
自定义 ObjectMapper(JacksonObjectMapper)对象转换器
java
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 为开发者提供了处理数据的新工具,尤其是在物联网、网络通信和存储系统等领域。
示例数据
假设我们有一个简单的字典对象,内容如下:
java
{
"name": "Alice",
"age": 30,
"isStudent": false,
"courses": ["Math", "Science"],
"grades": {
"Math": 90,
"Science": 85
}
}
转换为 CBOR
将上述 JSON 数据转换为 CBOR 格式后,它的二进制表示可能类似于以下内容(注意:实际的二进制数据会因实现而异,以下为示意):
java
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
库来实现:
python
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,以及如何使用库进行编码和解码。