我们以日期类型为例,把它作为请求参数和响应字段进行说明,默认的日期字段格式为ISO 8601标准,DateTimeFormat.ISO.DATE_TIME
,格式为yyyy-MM-dd'T'HH:mm:ss
,与咱们常用的日期时间有所不同,所以咱们需要重新定义一下。
本文功能
- 统一了日期参数,由传入的字符串传为java对象
- 统一了返回实体的日期字段,默认是iso8601
- 统一了返回实体的长整型返回值精度丢失问题,统一传为字符串
请求参数统一处理
- 请求参数前端输入的是字符串
- 接口类型LocalDate 传入的格式匹配yyyy-MM-dd
- 接口类型LocalTime 传入的格式匹配HH:mm:ss
- 接口类型LocalDateTime 传入的格式匹配yyyy-MM-dd'T'HH:mm:ss
/*** WebMvc配置.** @author lind* @date 2023/5/24 14:46* @since 1.0.0*/
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {static DateTimeFormatter DT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");static DateTimeFormatter T_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");static DateTimeFormatter D_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");/*** 增加GET请求参数中时间类型转换,注意是LocalTime,LocalDate和LocalDateTime,因为你配置的是DateTimeFormatter.* <ul>* <li>HH:mm:ss -> LocalTime</li>* <li>yyyy-MM-dd -> LocalDate</li>* <li>yyyy-MM-dd HH:mm:ss -> LocalDateTime</li>* </ul>* @param registry*/@Overridepublic void addFormatters(FormatterRegistry registry) {DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();// 对输入参数转为LocalDate,LocalTime,LocalDateTime格式化registrar.setTimeFormatter(T_FORMATTER);registrar.setDateFormatter(D_FORMATTER);registrar.setDateTimeFormatter(DT_FORMATTER);registrar.registerFormatters(registry);// 对输入参数转为java.util.Date格式化registry.addFormatter(new CompositeFormatter());}/*** java.util.Date日期格式化.*/private static class CompositeFormatter implements Formatter<Date> {private final List<Formatter<Date>> formatters = Arrays.asList(new DateFormatter("yyyy-MM-dd HH:mm:ss"),new DateFormatter("yyyy-MM-dd"), new DateFormatter("HH:mm:ss"));@Overridepublic Date parse(String text, Locale locale) throws ParseException {for (Formatter<Date> formatter : formatters) {try {return formatter.parse(text, locale);}catch (ParseException ignored) {}}throw new ParseException("Unable to parse date: " + text, 0);}@Overridepublic String print(Date date, Locale locale) {return formatters.get(0).print(date, locale);}}}
响应体中字段的格式化
- 默认采用jackson进行java对象到json的格式化,我们也以这个为例
- 其实json序列化方式需要自行实现
/*** json响应配置. Long到字符串,避免Long被截取 Date日期格式化 LocalDate日期格式化** @author lind* @date 2023-08-16*/
@Configuration
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class) // 在JacksonAutoConfiguration之前加载
public class JacksonConfiguration {@Bean@ConditionalOnMissingBeanpublic Jackson2ObjectMapperBuilderCustomizer customizer() {return builder -> {builder.locale(Locale.CHINA);builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));// 早期的Date类型的格式化,默认的返回日期2022-04-21T10:28:00,添加后返回日期2022-04-21 10:28:07builder.simpleDateFormat(JavaTimeModule.NORM_DATETIME_PATTERN);// java8建议的LocalDate,LocalDateTime,LocalTime的格式化builder.modules(new JavaTimeModule());// Long 类型转 String 类型,避免js丢失精度builder.serializerByType(Long.class, ToStringSerializer.instance);};}}
JavaTimeModule可以根据自己的地区去配置
public class JavaTimeModule extends SimpleModule {public static final String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";public static final DateTimeFormatter NORM_DATETIME_FORMATTER = createFormatter(NORM_DATETIME_PATTERN);public JavaTimeModule() {super(PackageVersion.VERSION);// ======================= 时间序列化规则 ===============================// yyyy-MM-dd HH:mm:ssthis.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(NORM_DATETIME_FORMATTER));// yyyy-MM-ddthis.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));// HH:mm:ssthis.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));// Instant 类型序列化this.addSerializer(Instant.class, InstantSerializer.INSTANCE);// ======================= 时间反序列化规则 ==============================// yyyy-MM-dd HH:mm:ssthis.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(NORM_DATETIME_FORMATTER));// yyyy-MM-ddthis.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));// HH:mm:ssthis.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));// Instant 反序列化this.addDeserializer(Instant.class, InstantDeserializer.INSTANT);}public static DateTimeFormatter createFormatter(String pattern) {return DateTimeFormatter.ofPattern(pattern, Locale.getDefault()).withZone(ZoneId.systemDefault());}}