美文网首页
SpringBoot对接收及返回Instant类型的处理

SpringBoot对接收及返回Instant类型的处理

作者: 爱的旋转体 | 来源:发表于2018-11-21 17:40 被阅读0次

    一:处理post请求json中的Instant类型
    1.springboot中日期格式化配置:

    spring:
        jackson:
            date-format: yyyy-MM-dd HH:mm:ss
            time-zone: GMT+8
    

    以上配置只对Date类型的日期格式化有效,对LocalDateTime ,Instant无效,需要添加以下配置:

    package com.mycompany.myapp.config;
    
    import java.io.IOException;
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.time.Instant;
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.time.format.DateTimeFormatter;
    import java.util.Date;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.zalando.problem.ProblemModule;
    import org.zalando.problem.violations.ConstraintViolationProblemModule;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializationFeature;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import com.fasterxml.jackson.databind.ser.std.DateSerializer;
    import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
    import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
    import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
    import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
    import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
    import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
    import com.mycompany.myapp.utils.DateFormatUtil;
    
    @Configuration
    public class JacksonConfiguration {
    
        @Value("${spring.jackson.date-format}")
        private String formatValue;
    
        @Bean(name = "format")
        public DateTimeFormatter format() {
            return DateTimeFormatter.ofPattern(formatValue);
        }
    
        @Bean
        public ObjectMapper serializingObjectMapper(@Qualifier("format") DateTimeFormatter format) {
            JavaTimeModule javaTimeModule = new JavaTimeModule();
            javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(format));
            javaTimeModule.addSerializer(Instant.class, new InstantCustomSerializer(format));
            javaTimeModule.addSerializer(Date.class, new DateSerializer(false, new SimpleDateFormat(formatValue)));
            javaTimeModule.addDeserializer(Instant.class, new InstantCustomDeserializer());
            javaTimeModule.addDeserializer(Date.class, new DateCustomDeserializer());
            ObjectMapper mapper = new ObjectMapper()
                    .registerModule(new ParameterNamesModule())
                    .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                    .registerModule(javaTimeModule);
            return mapper;
        }
    
        class InstantCustomSerializer extends JsonSerializer<Instant> {
            private DateTimeFormatter format;
    
            private InstantCustomSerializer(DateTimeFormatter formatter) {
                this.format = formatter;
            }
    
            @Override
            public void serialize(Instant instant, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
                if (instant == null) {
                    return;
                }
                String jsonValue = format.format(instant.atZone(ZoneId.systemDefault()));
                jsonGenerator.writeString(jsonValue);
            }
        }
    
        class InstantCustomDeserializer extends JsonDeserializer<Instant>{
    
            @Override
            public Instant deserialize(JsonParser p, DeserializationContext ctxt)
                    throws IOException, JsonProcessingException {
                String dateString = p.getText().trim();
                if(StringUtils.isNotBlank(dateString)){
                    Date pareDate;
                    try {
                        pareDate = DateFormatUtil.pareDate(dateString);
                        if(null != pareDate){
                            return pareDate.toInstant();
                        }
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
    
        }
    
        class DateCustomDeserializer extends JsonDeserializer<Date>{
    
            @Override
            public Date deserialize(JsonParser p, DeserializationContext ctxt)
                    throws IOException, JsonProcessingException {
                String dateString = p.getText().trim();
                if(StringUtils.isNotBlank(dateString)){
                    try {
                        return DateFormatUtil.pareDate(dateString);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                return null;
            }
    
        }
    
        /**
         * Support for Java date and time API.
         * @return the corresponding Jackson module.
         */
        @Bean
        public JavaTimeModule javaTimeModule() {
            return new JavaTimeModule();
        }
    
        @Bean
        public Jdk8Module jdk8TimeModule() {
            return new Jdk8Module();
        }
    
    
        /*
         * Support for Hibernate types in Jackson.
         */
        @Bean
        public Hibernate5Module hibernate5Module() {
            return new Hibernate5Module();
        }
    
        /*
         * Jackson Afterburner module to speed up serialization/deserialization.
         */
        @Bean
        public AfterburnerModule afterburnerModule() {
            return new AfterburnerModule();
        }
    
        /*
         * Module for serialization/deserialization of RFC7807 Problem.
         */
        @Bean
        ProblemModule problemModule() {
            return new ProblemModule();
        }
    
        /*
         * Module for serialization/deserialization of ConstraintViolationProblem.
         */
        @Bean
        ConstraintViolationProblemModule constraintViolationProblemModule() {
            return new ConstraintViolationProblemModule();
        }
    
    }
    
    package com.mycompany.myapp.utils;
    
    import java.text.ParseException;
    import java.time.Instant;
    import java.util.Date;
    
    import javax.validation.constraints.NotNull;
    
    import org.apache.commons.lang3.StringUtils;
    import org.apache.commons.lang3.time.FastDateFormat;
    
    /**
    * @author xuzhipeng
    * @date 2018-11-22 13:51:05
    * @since 1.0
    */
    public class DateFormatUtil {
    
        public static final String SYMBOL_DOT = "\\.";
    
        public static final String DATE_REGEX_YYYYMM = "^\\d{4}-\\d{1,2}$";//日期正则yyyy-MM
        public static final String DATE_REGEX_YYYYMMDD = "^\\d{4}-\\d{1,2}-\\d{1,2}$";//日期正则yyyy-MM-dd
        public static final String DATE_REGEX_YYYYMMDDHHMM = "^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}$";//日期正则yyyy-MM-dd hh:mm
        public static final String DATE_REGEX_YYYYMMDDHHMMSS = "^\\d{4}-\\d{1,2}-\\d{1,2} {1}\\d{1,2}:\\d{1,2}:\\d{1,2}$";//日期正则yyyy-MM-dd hh:mm:ss
        public static final String DATE_REGEX_SECOND_DOT_NANOSECOND = "^[0-9]{1,}\\.[0-9]{1,9}$";//Instant日期秒+纳秒
        public static final String DATE_REGEX_YYYYMMDD_T_HHMMSS_Z = "^\\d{4}-\\d{1,2}-\\d{1,2}T\\d{1,2}:\\d{1,2}:\\d{1,2}Z$";//日期正则yyyy-MM-dd'T'HH:mm:ssZ
        public static final String DATE_REGEX_YYYYMMDD_T_HHMMSS_SSS_Z = "^\\d{4}-\\d{1,2}-\\d{1,2}T\\d{1,2}:\\d{1,2}:\\d{1,2}\\.\\d{1,3}Z$";//日期正则yyyy-MM-dd'T'HH:mm:ss.SSSZ
    
    
        // 以T分隔日期和时间,并带时区信息,符合ISO8601规范
        public static final String PATTERN_ISO = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
        public static final String PATTERN_ISO_ON_SECOND = "yyyy-MM-dd'T'HH:mm:ssZZ";
        public static final String PATTERN_ISO_ON_DATE = "yyyy-MM-dd";
        public static final String PATTERN_ISO_ON_MONTH = "yyyy-MM";
    
        // 以空格分隔日期和时间,不带时区信息
        public static final String PATTERN_DEFAULT = "yyyy-MM-dd HH:mm:ss.SSS";
        public static final String PATTERN_DEFAULT_ON_SECOND = "yyyy-MM-dd HH:mm:ss";
        public static final String PATTERN_DEFAULT_ON_MINUTE = "yyyy-MM-dd HH:mm";
    
        // 使用工厂方法FastDateFormat.getInstance(), 从缓存中获取实例
    
        // 以T分隔日期和时间,并带时区信息,符合ISO8601规范
        public static final FastDateFormat ISO_FORMAT = FastDateFormat.getInstance(PATTERN_ISO);
        public static final FastDateFormat ISO_ON_SECOND_FORMAT = FastDateFormat.getInstance(PATTERN_ISO_ON_SECOND);
        public static final FastDateFormat ISO_ON_DATE_FORMAT = FastDateFormat.getInstance(PATTERN_ISO_ON_DATE);
        public static final FastDateFormat ISO_ON_MONTH_FORMAT = FastDateFormat.getInstance(PATTERN_ISO_ON_MONTH);
    
        // 以空格分隔日期和时间,不带时区信息
        public static final FastDateFormat DEFAULT_FORMAT = FastDateFormat.getInstance(PATTERN_DEFAULT);
        public static final FastDateFormat DEFAULT_ON_SECOND_FORMAT = FastDateFormat.getInstance(PATTERN_DEFAULT_ON_SECOND);
        public static final FastDateFormat DEFAULT_ON_MINUTE_FORMAT = FastDateFormat.getInstance(PATTERN_DEFAULT_ON_MINUTE);
    
        /**
         * 将日期格式的字符串转换成指定格式的日期
         * @param pattern 日期格式
         * @param dateString 日期字符串
         * @return
         * @throws ParseException
         */
        public static Date pareDate(@NotNull String pattern, @NotNull String dateString) throws ParseException {
            return FastDateFormat.getInstance(pattern).parse(dateString);
        }
    
        /**
         * 将日期格式的字符串根据正则转换成相应格式的日期
         * @param dateString 日期字符串
         * @return
         * @throws ParseException
         */
        public static Date pareDate(@NotNull String dateString) throws ParseException {
            String source = dateString.trim();
            if (StringUtils.isNotBlank(source)) {
                if(source.matches(DATE_REGEX_YYYYMM)){
                    return ISO_ON_MONTH_FORMAT.parse(source);
                }else if(source.matches(DATE_REGEX_YYYYMMDD)){
                    return ISO_ON_DATE_FORMAT.parse(source);
                }else if(source.matches(DATE_REGEX_YYYYMMDDHHMM)){
                    return DEFAULT_ON_MINUTE_FORMAT.parse(source);
                }else if(source.matches(DATE_REGEX_YYYYMMDDHHMMSS)){
                    return DEFAULT_ON_SECOND_FORMAT.parse(source);
                }else if(source.matches(DATE_REGEX_YYYYMMDD_T_HHMMSS_Z)){
                    return ISO_ON_SECOND_FORMAT.parse(source);
                }else if(source.matches(DATE_REGEX_YYYYMMDD_T_HHMMSS_SSS_Z)){
                    return ISO_FORMAT.parse(source);
                }else if(source.matches(DATE_REGEX_SECOND_DOT_NANOSECOND)){
                    String[] split = source.split(SYMBOL_DOT);
                    return Date.from(Instant.ofEpochSecond(Long.parseLong(split[0]), Long.parseLong(split[1])));
                }else {
                    throw new IllegalArgumentException("Invalid date value '" + source + "'");
                }
            }
            return null;
        }
    
    }
    

    并在pom文件中添加以下依赖:

    <dependency>
        <groupId>com.fasterxml.jackson.module</groupId>
        <artifactId>jackson-module-parameter-names</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jdk8</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
    </dependency>
    <dependency>
         <groupId>org.apache.commons</groupId>
         <artifactId>commons-lang3</artifactId>
    </dependency>
    

    参考:
    1.http://www.cnblogs.com/liwc/p/9621435.html;
    2.https://my.oschina.net/MeiJianMing/blog/1859609;
    3.https://blog.csdn.net/howinfun/article/details/79271404

    二:对get请求中的Instant类型
    1.定义全局Instant日期类型转换器:

    package com.mycompany.myapp.config;
    
    import java.text.ParseException;
    import java.time.Instant;
    import java.util.Date;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.stereotype.Component;
    
    import com.mycompany.myapp.utils.DateFormatUtil;
    
    /**
    * @author xuzhipeng
    * @date 2019-03-20 18:02:41
    * @since 1.0
    */
    @Component
    public class InstantConverter implements Converter<String,Instant> {
    
        @Override
        public Instant convert(String source) {
            String dateString = source.trim();
            if(StringUtils.isNotBlank(dateString)){
                Date pareDate;
                try {
                    pareDate = DateFormatUtil.pareDate(dateString);
                    if(null != pareDate){
                        return pareDate.toInstant();
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    
    }
    

    2.springboot2.0以上只配置全局转换器不生效,需要加以下代码:

    package com.mycompany.myapp.config;
    
    import java.util.Set;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.event.ContextRefreshedEvent;
    import org.springframework.core.convert.ConversionService;
    import org.springframework.core.convert.converter.Converter;
    import org.springframework.core.convert.support.GenericConversionService;
    import org.springframework.stereotype.Component;
    
    /**
     * @author xuzhipeng
     * @date 2019-03-22 16:04:49
     * @since 1.0
     */
    @Component
    public class SpringContextListener implements ApplicationListener<ContextRefreshedEvent> {
        @Autowired
        private Set<Converter<?, ?>> converters;
        @Autowired
        private ConversionService conversionService;
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            GenericConversionService gcs = (GenericConversionService) conversionService;
            for (Converter<?, ?> converter : converters) {
                gcs.addConverter(converter);
            }
        }
    }
    

    参考:
    1.https://github.com/spring-projects/spring-boot/issues/6222
    2.https://github.com/spring-projects/spring-framework/issues/11081
    3.https://blog.csdn.net/qq_31871785/article/details/72863289

    三:实体类中的Instant类型返回yyyy-MM-dd格式:

    package com.mycompany.myapp.config;
    
    import java.io.IOException;
    import java.time.Instant;
    import java.time.ZoneId;
    import java.time.format.DateTimeFormatter;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import com.fasterxml.jackson.databind.ser.std.StdSerializer;
    
    /**
     * @author xuzhipeng
     * @date 2019-03-26 14:36:44
     * @since 1.0
     */
    public class CustomInstantDateSerializer extends StdSerializer<Instant> {
    
        private static final long serialVersionUID = 1L;
    
        private static DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    
        public CustomInstantDateSerializer() {
            this(null);
        }
    
        public CustomInstantDateSerializer(Class<Instant> t) {
            super(t);
        }
    
        @Override
        public void serialize(Instant instant, JsonGenerator jsonGenerator, SerializerProvider provider)
                throws IOException {
            if (instant == null) {
                return;
            }
            String jsonValue = format.format(instant.atZone(ZoneId.systemDefault()));
            jsonGenerator.writeString(jsonValue);
        }
    }
    
    public class Event {
        public String name;
     
        @JsonSerialize(using = CustomInstantDateSerializer.class)
        public Instant eventDate;
    }
    

    参考:
    1.https://www.baeldung.com/jackson-serialize-dates

    相关文章

      网友评论

          本文标题:SpringBoot对接收及返回Instant类型的处理

          本文链接:https://www.haomeiwen.com/subject/urgcqqtx.html