[Java]-HTTP请求中RestAPI接口中时间序列化处理

网络传输时需要将对象转换为字节流,这时就需要把对象进行序列化;在接收时,需要进行反序列化,把字节流转换为对象。

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。
Java中可方便地通过JackSON(参见:《Jackson使用简介与示例》)进行序列化与反序列化。但是因时间格式的复杂与多样性,经常会遇到序列化出错的情况,这时就需要进行特殊处理。

参数中时间处理

以参数方式传递的时间,

public ResponseResult listTest(@RequestParam LocalDateTime dtStart, @RequestParam(required = false) LocalDateTime dtEnd)
{ }

时间字符串作为普通请求参数传入时,转换用的是Converter;此时需要通过Configure来注入Bean,以定制时间的格式化方式:

@Configuration
public class JsonConfig {
    static final String DateUndefined = "undefined";

    @Bean
    public Converter<String, LocalDate> LocalDateConvert() {
        return new Converter<String, LocalDate>() {
            @Override
            public LocalDate convert(String source) {
                if (source == null || source.length() == 0)
                    return null;

                // return LocalDate.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                try {
                    return LocalDate.parse(source, DateTimeFormatter.ISO_LOCAL_DATE);
                } catch (DateTimeParseException ex) {
                    if (!source.equals(DateUndefined)) {
                        return null;
                    } else {
                         throw ex;
                    }
                }
            }

        };
    }

    @Bean
    public Converter<String, LocalDateTime> LocalDateTimeConvert() {
        return new Converter<String, LocalDateTime>() {
            @Override
            public LocalDateTime convert(String source) {
                if (source == null || source.length() == 0)
                    return null;

                try {
                    return LocalDateTime.parse(source, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                } catch (DateTimeParseException ex) {
                    if (source.equals(DateUndefined)) {
                        return null;
                    }
                }

                try {
                    return LocalDateTime.parse(source, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                } catch (DateTimeParseException ex) {
                    throw ex;
                }
            }
        };
    }
}

body中时间处理

Body中的时间是使用的Jackson等Json序列化器完成的。

注解方式@JsonFormat

通过@JsonFormat注解,可以设定时间的格式化方式:

@Data
public class TestData {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime logTime;
}

这种方式需要针对每个实体进行设定,且只能是一种固定的格式,复杂且不灵活。

修改Json序列化器

默认情况下,时间是通过LocalDateTimeDeserializer进行反序列化的,若要定制在需要对其进行扩展。

扩展序列化器

只需继承LocalDateTimeDeserializer,对其进行扩展即可:

public class WebLocalDateTimeDeserializer extends LocalDateTimeDeserializer {
    static final String DateUndefined = "undefined";

    public WebLocalDateTimeDeserializer(DateTimeFormatter formatter){
        super(formatter);
    }

    @Override
    public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        if (parser.hasTokenId(JsonTokenId.ID_STRING)) {
            String string = parser.getText().trim();
            if (string.length() == 0 || DateUndefined.equals(string)) {
                return null;
            }
        }

        return super.deserialize(parser, context);
    }
}

对于特殊情形,只需在if部分处理即可,最后再调用父类的deserialize对标准格式的时间进行反序列化。

添加序列化器

要使定制生效,需要把序列化器添加到转换器列表中:

@Configuration
public class WebLocalDateConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        JavaTimeModule module = new JavaTimeModule();
       module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 这里添加的是自定义的反序列化器
        module.addDeserializer(LocalDateTime.class,
                new WebLocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
        mapper.registerModule(module);

        // add converter at the very front
        // if there are same type mappers in converters, setting in first mapper is used.
        int i=0;
        for(HttpMessageConverter con : converters){
            if(con instanceof MappingJackson2HttpMessageConverter){
                break;
            }
            ++i;
        }
        converters.add(i, new MappingJackson2HttpMessageConverter(mapper));
    }
}

在序列化时,会优先使用最先查找到的序列化器;为使我们的序列化器生效,必须保证其加载到其他同类型序列化器前面;但是不能放在最前面,否则可能会影响其他类型字符串的序列化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值