如何优雅的接收时间类型参数?

时间的格式有很多种,比较常用的有时间戳格式、UTC时间格式、标准时间格式等,而且时间参数出现的位置可能在URL上,可能在Body中,也可能在Header中,我们创建一个简单的接口,想通过@PathVariable接收Date类型的时间参数,和通过@RequestParam接收LocalDateTime类型的时间参数,并且想通过@RequestBody来接收JSON中的时间参数:

图片


js

GET http://localhost:80/time/2023-09-10?time=2023-09-15 11:11:11
Accept: application/json
Content-Type: application/json

{
"id":1,
"now":"2023-09-15 13:50:10",
"day":"2023-09-15",
"time": "2023-09-15 13:50:10",
"timeStack": 1694757010407
}

SpringBoot默认是用String接收的,如果直接用LocalDateTime或者Date来接收会报一个类型转换错误。

当然我们可以使用String接收,再手动转成对应的时间格式,但是不够优雅,接下来我们看看不同级别是如何处理时间字段的。

青铜解决方案

图片

图片

青铜解析方案存在的问题:

  1. @InitBinder作用域只是当前的Controller,如果我用100个Controller难道我要写100个@InitBinder

  2. @JsonFormat 也是每个字段上都要增加个注解,而且只能支持一种时间格式,如果我们还要支持时间戳格式就没法做到了。

白银解决方案

针对青铜解析方案存在的问题1,我们的解决方案是使用@ControllerAdvice,这样就不用在每个Controller上都添加@InitBinder


java

@ControllerAdvice
public class GlobalControllerAdvice {

@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(LocalDateTime.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
setValue(DateUtil.parseLocalDateTime(text));
}
});
binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
setValue(DateUtil.parse(text,NORM_DATETIME_PATTERN,NORM_DATE_PATTERN));
}
});
}
}

图片


java

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
@Primary
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
module.addSerializer(Date.class, new DateTimeSerializer());
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
module.addDeserializer(Date.class, new DateTimeDeserializer());
mapper.registerModule(module);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return JsonUtils.getMapper();
}
}

public class DateTimeDeserializer extends StdDeserializer<Date> {

public DateTimeDeserializer() {
this(null);
}

public DateTimeDeserializer(Class<?> vc) {
super(vc);
}

@Override
public Date deserialize(JsonParser jp, DeserializationContext ctx)
throws IOException {
String value = jp.getValueAsString();
return DateUtil.parse(value,NORM_DATETIME_PATTERN,NORM_DATE_PATTERN);
}
}

public class DateTimeSerializer extends StdSerializer<Date> {

public DateTimeSerializer() {
this(null);
}

public DateTimeSerializer(Class<Date> t) {
super(t);
}

@Override
public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeString(DateUtil.format(value, DatePattern.NORM_DATETIME_PATTERN));
}
}

public class LocalDateTimeDeserializer extends StdDeserializer<LocalDateTime> {

public LocalDateTimeDeserializer() {
this(null);
}

public LocalDateTimeDeserializer(Class<?> vc) {
super(vc);
}

@Override
public LocalDateTime deserialize(JsonParser jp, DeserializationContext ctx)
throws IOException {
String value = jp.getValueAsString();
if (StrUtil.isNumeric(value)) {
Date date = new Date(jp.getLongValue());
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.of("Asia/Shanghai"));
} else {
return DateUtil.parseLocalDateTime(value);
}
}
}

public class LocalDateTimeSerializer extends StdSerializer<LocalDateTime> {

public LocalDateTimeSerializer() {
this(null);
}

public LocalDateTimeSerializer(Class<LocalDateTime> t) {
super(t);
}

@Override
public void serialize(LocalDateTime value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeString(LocalDateTimeUtil.formatNormal(value));
}
}

图片

王者解决方案

图片


java

@Configuration
public class WebConfig {
@Bean
@Primary
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
module.addSerializer(Date.class, new DateTimeSerializer());
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
module.addDeserializer(Date.class, new DateTimeDeserializer());
mapper.registerModule(module);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return JsonUtils.getMapper();
}

@Bean
public Converter<String, LocalDateTime> stringLocalDateTimeConverter() {
return new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String source) {
if (StrUtil.isNumeric(source)) {
return LocalDateTimeUtil.of(Long.parseLong(source));
} else {
return DateUtil.parseLocalDateTime(source);
}
}
};

}

@Bean
public Converter<String, Date> stringDateTimeConverter() {
return new Converter<String, Date>() {
@Override
public Date convert(String source) {
if (StrUtil.isNumeric(source)) {
return new Date(Long.parseLong(source));
} else {
return DateUtil.parse(source);
}
}
};
}

}

最后说一句(求关注!别白嫖!)

如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。

关注公众号:woniuxgg,在公众号中回复:笔记  就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值