当然可以
想想看我们在项目中什么时候会用到这两个注解呢?
- Get请求传入java.util.Date、java.time.xxx类型参数,需要配上@DateTimeFormat来解析
- Post请求传入json时候,同样需要在上述两种时间属性上加@JsonFormat来反序列化
- 返回对象里有java.util.Date需加@JsonFormat,配置好时区,不然时间会少8小时
先看看平常我们是怎么使用这两个注解的
@DateTimeFormat@GetMapping("test") public Stu testGet(Stu stu) { log.info("stu get: " + stu); return stu; }
@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';
@JsonFormat
@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":
所以有了这两个注解,就能很好解决项目开发中参数入参、出参的问题。
但是,很多地方使用了这些注解时候,就要想想有没有全局统一配置呢?
下面给出全局配置的代码
核心依赖定义一些常量和Converterorg.springframework.boot spring-boot-starter-weborg.projectlombok lomboktrue cn.hutool hutool-all5.6.6 commons-lang commons-lang2.6
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配置入参解析{ @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 { @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 { @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 { @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 { @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() { @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 () { @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 () { @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 () { @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); } }
现在可以愉快的开发啦 不用再担心日期时间不能被解析,也不用担心时区问题导致时间不准确的问题。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)