当然可以
想想看我们在项目中什么时候会用到这两个注解呢?
java.util.Date
、java.time.xxx
类型参数,需要配上@DateTimeFormat
来解析@JsonFormat
来反序列化java.util.Date
需加@JsonFormat
,配置好时区,不然时间会少8小时先看看平常我们是怎么使用这两个注解的
@GetMapping("test")
public Stu testGet(Stu stu) {
log.info("stu get: " + stu);
return stu;
}
/**
* 学生
* @author wangwenwen
* @date 2021/10/19 12:54
* @version v1.0.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Stu {
// 姓名
private String name;
// 生日
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birth;
// 毕业时间
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date graduate;
}
这两个参数如果不加@DateTimeFormat
注解的话,会报以下的错误
Resolved [org.springframework.validation.BindException:
org.springframework.validation.BeanPropertyBindingResult: 2 errors
...省略一些日志...
[Failed to convert property value of type 'java.lang.String' to required type 'java.time.LocalDateTime' for property 'birth';
...省略一些日志...
[Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for
property 'graduate';
@PostMapping("test")
public Stu testPost(@RequestBody Stu stu) {
log.info("stu post: " + stu);
return stu;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Stu {
// 姓名
private String name;
// 生日
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birth;
// 毕业时间
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date graduate;
}
如果不加@JsonFormat
注解,则会报序列化错误
Resolved [org.springframework.http.converter.HttpMessageNotReadableException:
...省略部分日志... Failed to deserialize java.time.LocalDateTime: (java.time.format.DateTimeParseException)
...省略部分日志... JSON parse error: Cannot deserialize value of type `java.util.Date`
from String "2029-01-01 10:00:00": not a valid representation
(error: Failed to parse Date value '2029-01-01 10:00:00': Cannot parse date "2029-01-01 10:00:00":
所以有了这两个注解,就能很好解决项目开发中参数入参、出参的问题。
但是,很多地方使用了这些注解时候,就要想想有没有全局统一配置呢?
下面给出全局配置的代码
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.6.6version>
dependency>
<dependency>
<groupId>commons-langgroupId>
<artifactId>commons-langartifactId>
<version>2.6version>
dependency>
dependencies>
public class DateConfig {
/**
* 默认日期时间格式
*/
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
/**
* 默认日期格式
*/
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
/**
* 默认时间格式
*/
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
/**
* 默认年月格式
*/
public static final String DEFAULT_YEAR_MONTH_FORMAT = "yyyy-MM";
static class LocalDateTimeConverter implements Converter<String, LocalDateTime> {
@Override
public LocalDateTime convert(String source) {
if (StringUtils.isBlank(source)) {
return null;
}
if (StringUtils.isNumeric(source)) {
return Instant.ofEpochMilli(Long.parseLong(source)).atZone(ZoneId.systemDefault()).toLocalDateTime();
} else {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT));
}
}
}
static class LocalDateConverter implements Converter<String, LocalDate> {
@Override
public LocalDate convert(String source) {
if (StringUtils.isBlank(source)) {
return null;
}
if (StringUtils.isNumeric(source)) {
return Instant.ofEpochMilli(Long.parseLong(source)).atZone(ZoneId.systemDefault()).toLocalDate();
} else {
return LocalDate.parse(source, DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT));
}
}
}
static class LocalTimeConverter implements Converter<String, LocalTime> {
@Override
public LocalTime convert(String source) {
if (StringUtils.isBlank(source)) {
return null;
}
return LocalTime.parse(source, DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
}
}
static class YearMonthConverter implements Converter<String, YearMonth> {
@Override
public YearMonth convert(String source) {
if (StringUtils.isBlank(source)) {
return null;
}
return YearMonth.parse(source, DateTimeFormatter.ofPattern(DEFAULT_YEAR_MONTH_FORMAT));
}
}
static class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
if (StringUtils.isBlank(source)) {
return null;
}
if (StringUtils.isNumeric(source)) {
return new Date(Long.parseLong(source));
} else {
return DateUtil.parse(source);
}
}
}
}
@Configuration
public class ServletContextConfig implements WebMvcConfigurer {
// 解析时间入参
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new DateConfig.LocalDateConverter());
registry.addConverter(new DateConfig.LocalDateTimeConverter());
registry.addConverter(new DateConfig.YearMonthConverter());
registry.addConverter(new DateConfig.LocalTimeConverter());
registry.addConverter(new DateConfig.DateConverter());
}
}
@Component
public class MyJackson2ObjectMapperBuilderCustomizer implements Jackson2ObjectMapperBuilderCustomizer {
@Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
JavaTimeModule javaTimeModule = new JavaTimeModule();
// =========================================== 序列化器 =========================================================
// LocalDateTime序列化器
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_TIME_FORMAT)));
// LocalDateTime序列化器
javaTimeModule.addSerializer(LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT)));
// LocalTime序列化器
javaTimeModule.addSerializer(LocalTime.class,
new LocalTimeSerializer(DateTimeFormatter.ofPattern(DateConfig.DEFAULT_TIME_FORMAT)));
// YearMonth序列化器
javaTimeModule.addSerializer(YearMonth.class,
new YearMonthSerializer(DateTimeFormatter.ofPattern(DateConfig.DEFAULT_YEAR_MONTH_FORMAT)));
// Date序列化器
javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(DateUtil.format(date, DateConfig.DEFAULT_DATE_TIME_FORMAT));
}
});
// =========================================== 反序列化器 =======================================================
// LocalDateTime反序列化器
javaTimeModule.addDeserializer(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String text = p.getText();
if (StringUtils.isEmpty(text)) {
return null;
}
if (StringUtils.isNumeric(text)) {
return Instant.ofEpochMilli(Long.parseLong(text)).atZone(ZoneId.systemDefault()).toLocalDateTime();
} else {
return LocalDateTime.parse(text, DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_TIME_FORMAT));
}
}
});
// LocalDate反序列化器
javaTimeModule.addDeserializer(LocalDate.class, new JsonDeserializer<LocalDate>() {
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String text = p.getText();
if (StringUtils.isBlank(text)) {
return null;
}
if (StringUtils.isNumeric(text)) {
return Instant.ofEpochMilli(Long.parseLong(text)).atZone(ZoneId.systemDefault()).toLocalDate();
} else {
return LocalDate.parse(text, DateTimeFormatter.ofPattern(DateConfig.DEFAULT_DATE_FORMAT));
}
}
});
// LocalTime反序列化器
javaTimeModule.addDeserializer(LocalTime.class,
new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DateConfig.DEFAULT_TIME_FORMAT)));
// YearMonth反序列化器
javaTimeModule.addDeserializer(YearMonth.class,
new YearMonthDeserializer(DateTimeFormatter.ofPattern(DateConfig.DEFAULT_YEAR_MONTH_FORMAT)));
// Date反序列化器
javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String text = p.getText();
if (StringUtils.isBlank(text)) {
return null;
}
if (StringUtils.isNumeric(text)) {
return new Date(Long.parseLong(text));
} else {
return DateUtil.parse(text);
}
}
});
// 添加进去
jacksonObjectMapperBuilder.modules(javaTimeModule);
}
}
现在可以愉快的开发啦 不用再担心日期时间不能被解析,也不用担心时区问题导致时间不准确的问题。