这里采用实现WebMvcConfigurer接口,通过实现extendMessageConverters
方法来扩展消息转换器,实现日期格式的统一处理。
1. 简单实现
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.fasterxml.jackson.databind.ObjectMapper;
@Configuration // 表明这是一个 Spring 配置类,Spring 容器会自动扫描并加载该配置
public class WebConfig implements WebMvcConfigurer {
/**
* 扩展 Spring MVC 框架的消息转换器
* 这里是通过自定义 Jackson 的 `MappingJackson2HttpMessageConverter` 来处理 JSON 数据
* 并为其设置自定义的日期格式
*
* @param converters Spring MVC 自动传入的消息转换器列表
*/
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// 输出日志,提示消息转换器正在被扩展
log.info("扩展消息转换器...");
// 创建一个 JSON 消息转换器对象
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 创建一个 ObjectMapper(这是 Jackson 用于将 Java 对象和 JSON 相互转换的工具类)
ObjectMapper objectMapper = new ObjectMapper();
// 设置日期格式为 "yyyy-MM-dd HH:mm:ss",即:2024-10-15 12:34:56
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// 将配置好的 ObjectMapper 设置到消息转换器中
converter.setObjectMapper(objectMapper);
// 将自定义的消息转换器添加到转换器列表的最前面
// 这样 Spring MVC 会优先使用这个自定义的转换器
converters.add(0, converter);
}
}
1.1 主要特点
1.1.1 简单的日期格式配置
这段代码主要通过 ObjectMapper#setDateFormat
方法配置了一个全局的日期格式。它只针对日期格式进行设置,格式为 "yyyy-MM-dd HH:mm:ss"
。在 JSON 数据的序列化和反序列化过程中,所有的 Date
对象都会被转换成这个格式。
1.1.2 局限性
- 这种方式仅适用于
java.util.Date
类和类似的java.sql.Date
、java.sql.Timestamp
。对于 Java 8 引入的日期时间 API(如LocalDateTime
、LocalDate
)并没有处理。 - 处理方式较为简单,只适用于某些特定场景。
1.2 适用场景
-
简单日期处理需求:如果项目中主要处理的是
java.util.Date
或java.sql.Date
这类传统的日期时间类型,而没有使用 Java 8 引入的日期时间类(如LocalDate
,LocalDateTime
),那么这段代码足以胜任。这种场景一般在老旧项目或小型应用中较为常见。 -
快速实现统一日期格式化:如果你仅仅需要为整个应用程序统一格式化日期,而不需要处理其他复杂的序列化和反序列化要求,这种方法能快速有效地实现这一需求。
-
项目简单,开发周期较短:对于一些简单的 Web 项目或 REST API,尤其是那些不涉及复杂的日期时间操作或对兼容性要求较低的场景,这段代码可以满足需求。
-
无复杂 JSON 序列化需求:如果你的项目对 JSON 的序列化和反序列化没有太多特殊需求,且只需要格式化日期字段,并且你不想引入太多的复杂配置,这段代码足够简单清晰。
1.3 适用环境
- 传统的 Java Web 应用,使用的是 Java 7 或更早的版本,项目中可能没有用到 Java 8 的日期时间 API。
-
轻量级 Web 服务,仅需要处理简单的
Date
时间格式,没有更复杂的定制化需求。
2. 全面处理 Java 日期和时间 API
2.1 实现步骤
2.1.1 自定义ObjectMapper类
在自定义的ObjectMapper类中,全面处理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);
}
}
2.1.2 使用自定义的ObjectMapper
扩展消息转换器中使用自定义的ObjectMapper
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
// 创建一个 JSON 消息转换器对象
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
// 使用自定义的 JacksonObjectMapper
converter.setObjectMapper(new JacksonObjectMapper());
// 将自定义的消息转换器添加到转换器列表的最前面
converters.add(0, converter);
}
2.2 主要特点
-
全面处理 Java 日期和时间 API:
- 这段代码通过自定义的
JacksonObjectMapper
实现了对 Java 8 日期时间 API (LocalDate
,LocalDateTime
,LocalTime
) 的序列化和反序列化处理。通过使用SimpleModule
注册了自定义的序列化器和反序列化器,它们分别使用了特定的日期和时间格式。 - 日期格式不仅局限于
java.util.Date
,也适用于java.time.LocalDate
、LocalDateTime
和LocalTime
。
- 这段代码通过自定义的
-
自定义反序列化特性:
- 该代码使用
FAIL_ON_UNKNOWN_PROPERTIES
关闭了对未知属性的报错。在反序列化时,如果 JSON 中包含了 Java 类中没有定义的字段,代码不会抛出异常。这使得反序列化过程更加灵活,避免因版本问题或多余字段导致的错误。
- 该代码使用
-
更强的灵活性:
- 通过模块化的方式,将不同的序列化器和反序列化器进行注册,支持对各种复杂对象的灵活处理。适用范围更广,特别是对 Java 8 之后的日期时间 API 处理更加完善。
2.3 适用场景
-
使用 Java 8 日期时间 API 的项目:如果你的项目中广泛使用了 Java 8 引入的日期时间类(如
LocalDate
,LocalDateTime
,LocalTime
),并且需要对这些类型进行序列化和反序列化操作,第二段代码更为适合。它通过自定义ObjectMapper
配置了对这些新日期时间类的处理。 -
复杂日期时间处理需求:当你需要对不同的日期和时间格式进行精细控制,比如要分别处理日期、时间和日期时间,并且希望自定义它们的格式(如将时间格式设置为
"HH:mm:ss"
),第二段代码提供了更灵活的方案。 -
需要忽略未知属性的场景:如果你的项目可能会收到包含额外或未知字段的 JSON 数据,而你不希望反序列化时抛出异常(比如在多版本兼容的场景下),这段代码通过配置
FAIL_ON_UNKNOWN_PROPERTIES
来确保反序列化时能够兼容这些未知字段。 -
大型项目或微服务:在大型项目中,通常会涉及复杂的数据对象和灵活的 JSON 处理需求。此时,第二段代码的模块化扩展方式(通过
SimpleModule
注册序列化和反序列化器)使得它能够轻松处理不同的数据类型,具有较高的扩展性和灵活性。 -
多类型序列化需求:除了日期和时间之外,项目中可能需要对其他复杂的对象进行定制化的序列化和反序列化。这段代码通过
SimpleModule
机制,允许添加额外的序列化器和反序列化器,以满足更多复杂类型的需求。
2.4 适用环境
-
现代 Java 应用,使用了 Java 8 及以上版本,尤其是项目中广泛使用
LocalDateTime
、LocalDate
等 Java 8 日期时间类。 - 微服务架构项目,需要对不同的服务接口返回的 JSON 进行高度灵活的序列化和反序列化处理。
- 需要兼容多版本的项目,如果需要处理不同版本的 API 返回的数据,且 JSON 结构可能变化,此代码能够有效处理兼容性问题。
- 大中型企业级应用,需要对序列化过程进行定制化,比如处理不同格式的日期、忽略未知字段、或对不同对象类型进行特殊处理。
3. 总结
-
第一段代码 适合简单场景,项目对日期时间处理的要求不高,主要用于处理
Date
类的日期时间。 - 第二段代码 适合复杂场景,尤其是使用了 Java 8 日期时间 API 的项目,它能提供更强大的自定义功能和更灵活的序列化与反序列化处理。