spring mvc 接收 时间戳(Long)转 LocalDateTime
默认情况下,spring mvc 只接收 string 类型转成 LocalDateTime, 现要求 接收Long 类型时间戳要转成LocalDateTime, 又不想全局统一转,参照 @NumberFormat
实现 GET 请求接收 Long 转成 LocalDateTime
处理GET 请求
- RequestParamMethodArgumentResolver
- DataBinder
- ConversionService (如果配置了的话)
- GenericConversionService
- Converter (如果配置了的话)
- AnnotationFormatterFactory (注解方式)
- Converter (如果配置了的话)
- GenericConversionService
- ConversionService (如果配置了的话)
- DataBinder
可以发现 ,GET 请求接收前端参数是通过 Converter 来转换, 不过 这是统一处理的,如果要通过注解方式指定转换呢?
可以通过 AnnotationFormatterFactory 来实现
定义TimeStampFormat
/**
* 处理 GET 请求 timestamp 转成 LocalDateTime
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
public @interface TimeStampFormat {
}
对指定注解 类型解析
public class TimeStampToLocalDateTimeAnnotationFormatterFactory extends EmbeddedValueResolutionSupport
implements AnnotationFormatterFactory<TimeStampFormat> {
private static final Set<Class<?>> FIELD_TYPES;
static {
// Create the set of field types that may be annotated with @DateTimeFormat.
Set<Class<?>> fieldTypes = new HashSet<>(1);
fieldTypes.add(LocalDateTime.class);
FIELD_TYPES = Collections.unmodifiableSet(fieldTypes);
}
@Override
public final Set<Class<?>> getFieldTypes() {
return FIELD_TYPES;
}
@Override
public Printer<LocalDateTime> getPrinter(TimeStampFormat annotation, Class<?> fieldType) {
return new LongToLocalDateTimeParser();
}
@Override
@SuppressWarnings("unchecked")
public Parser<LocalDateTime> getParser(TimeStampFormat annotation, Class<?> fieldType) {
return new LongToLocalDateTimeParser();
}
class LongToLocalDateTimeParser implements Formatter<LocalDateTime> {
@Override
public LocalDateTime parse(String text, Locale locale) throws ParseException {
return Instant
.ofEpochMilli(Long.parseLong(text))
.atZone(ZoneOffset.ofHours(8))
.toLocalDateTime();
}
@Override
public String print(LocalDateTime object, Locale locale) {
return object.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + "";
}
}
}
向容器注册
@Configuration
public class CusWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldAnnotation(new TimeStampToLocalDateTimeAnnotationFormatterFactory());
}
}
dto:
@Data
public class UserDto {
/**
* GET 请求处理
*/
@TimeStampFormat
@JsonSerialize(using = LocalDateTimeToLongSerializer.class)
private LocalDateTime jsonFormatDateTime;
}
测试 :
@GetMapping("/test")
public UserDto userDto(UserDto query, @TimeStampFormat LocalDateTime paramTime) throws JsonProcessingException {
log.info(">>>request: {}", objectMapper.writeValueAsString(query));
UserDto userDto = new UserDto();
userDto.setDateTime(LocalDateTime.now());
userDto.setJsonFormatDateTime(LocalDateTime.now());
return userDto;
}
处理 POST 请求 @RequestBody
- RequestParamMethodArgumentResolver
- RequestResponseBodyMethodProcessor
- HttpMessageConverter
- GenericHttpMessageConverter
- AbstractJackson2HttpMessageConverter
- ObjectMapper
- AbstractJackson2HttpMessageConverter
- GenericHttpMessageConverter
- HttpMessageConverter
- RequestResponseBodyMethodProcessor
可以发现,@RequestBody最终交给 AbstractJackson2HttpMessageConverter (spring 默认), 而 AbstractJackson2HttpMessageConverter 交给 ObjectMapper 来序列化和反序列化
转时间戳
public class LocalDateTimeToLongSerializer extends JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
}
}
时间戳转 LocalDateTime
public class CustomLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
if (StrUtil.isEmpty(jsonParser.getText())) {
return null;
}
return Instant
.ofEpochMilli(Long.parseLong(jsonParser.getText()))
.atZone(ZoneOffset.ofHours(8))
.toLocalDateTime();
}
}
dto:
@Data
public class UserDto {
/**
* POST 处理
*/
@JsonSerialize(using = LocalDateTimeToLongSerializer.class)
@JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
private LocalDateTime dateTime;
}
测试:
@PostMapping("/test2")
public UserDto userDto2(@RequestBody UserDto query) throws JsonProcessingException {
log.info(">>>request: {}", objectMapper.writeValueAsString(query));
UserDto userDto = new UserDto();
userDto.setDateTime(LocalDateTime.now());
return userDto;
}
good luck!