在项目中日期格式化是最常见的问题,之前涉及的 java.util.Date 和 java.util.Calendar 类易用性差,不支持时区,非线程安全,对日期的计算方式繁琐,而且容易出错,因为月份是从0开始的,从 Calendar 中获取的月份需要加一才能表示当前月份。
在 JDK8 中,一个新的重要特性就是引入了全新的时间和日期API,它被收录在 java.time 包中,借助新的时间和日期API可以以更简洁的方法处理时间和日期。
下面我们通过一些配置实现对日期类型LocalDateTime的格式化
新建一个spring boot项目导入web依赖即可
org.springframework.boot spring-boot-starter-web
定义一个配置类,在里面定义两个 Bean
即可完成全局日期格式化处理,同时还兼顾了 Date
和 LocalDateTime
并存
package com.carry.config; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; @Configuration public class LocalDateTimeSerializerConfig { @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}") private String pattern; // 方案一 @Bean public LocalDateTimeSerializer localDateTimeDeserializer() { return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern)); } @Bean public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { return builder -> builder.serializerByType(LocalDateTime.class, localDateTimeDeserializer()); } }
package com.carry.dto; import java.time.LocalDateTime; public class Order { private LocalDateTime createTime; public LocalDateTime getCreateTime() { return createTime; } public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; } }
package com.carry.controller; import java.time.LocalDateTime; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.carry.dto.Order; @RestController @RequestMapping("/orders") public class OrderController { @GetMapping public Order query() { Order order = new Order(); order.setCreateTime(LocalDateTime.now()); return order; } }
启动项目并在浏览器中访问 http://localhost:8080/orders
有时候,我们对日期格式要做特殊的处理,全局的格式化方式无法满足我们需求是,使用该方案是非常好的选择,通过 @JsonFormat
注解我们可以更为精准的为日期字段格式化,它的优先级比方案一高,二者可结合使用
package com.carry.dto; import java.time.LocalDateTime; import com.fasterxml.jackson.annotation.JsonFormat; public class Order { @JsonFormat(pattern = "yyyy-MM-dd") private LocalDateTime createTime; public LocalDateTime getCreateTime() { return createTime; } public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; } }
重新启动项目并在浏览器中访问 http://localhost:8080/orders
其实和第一种类似,只不过第一种的写法更加优雅简洁,如果有多种类型需要做统一格式化处理,这种方案也不是不可以考虑(经测试不能与方案二同时使用)
package com.carry.config; import java.io.IOException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @Configuration public class LocalDateTimeSerializerConfig { @Value("${spring.jackson.date-format:yyyy-MM-dd HH:mm:ss}") private String pattern; // 方案三 @Bean @Primary public ObjectMapper serializingObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); JavaTimeModule javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer()); javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer()); objectMapper.registerModule(javaTimeModule); return objectMapper; } public class LocalDateTimeSerializer extends JsonSerializer{ @Override public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(value.format(DateTimeFormatter.ofPattern(pattern))); } } public class LocalDateTimeDeserializer extends JsonDeserializer { @Override public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext) throws IOException { return LocalDateTime.parse(p.getValueAsString(), DateTimeFormatter.ofPattern(pattern)); } } }
访问 http://localhost:8080/orders,发现 @JsonFormat 配置无效
推荐使用方案一与方案二