SpringBoot对接收及返回Instant类型的处理(转)
Posted 木西 - Muxy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot对接收及返回Instant类型的处理(转)相关的知识,希望对你有一定的参考价值。
一:处理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;
转自链接:https://www.jianshu.com/p/2908a2515e3e
以上是关于SpringBoot对接收及返回Instant类型的处理(转)的主要内容,如果未能解决你的问题,请参考以下文章
spring boot thymeleaf 后台返回boolean类型的怎么接收
函数——此函数只接收一个参数且此参数必须是列表数据类型,此函数完成的功能是返回给调用者一个字典, 此字典的键值对为此列表的索引及对应元素。例如传入的列表为:[11,22,33]返回的字典为{0:11,
函数——此函数只接收一个参数且此参数必须是列表数据类型,此函数完成的功能是返回给调用者一个字典, 此字典的键值对为此列表的索引及对应元素。例如传入的列表为:[11,22,33]返回的字典为{0:11,
在 Spring Boot 和 ElasticSearch 中使用 Instant、LocalDateTime 和 ZonedDateTime