package xyz.zq.sf.common.core.config;
import cn.hutool.core.date.DatePattern;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.PackageVersion;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import xyz.zq.sf.common.core.util.LocalDateTimeUtil;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.TimeZone;
/**
* jackson 配置
*
* @author hzq
* @date 2021-01-27 11:38
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JacksonConfiguration {
@Bean
@ConditionalOnMissingBean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
return jacksonObjectMapperBuilder -> {
jacksonObjectMapperBuilder.locale(Locale.CHINA);
jacksonObjectMapperBuilder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
jacksonObjectMapperBuilder.simpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance);
/*
* 当 Content-type: application/json
* 对时间类型 序列化及反序列化 格式的转换
*/
jacksonObjectMapperBuilder.modules(new SfLocalDateTimeModule());
};
}
/**
* 时间序列化格式转换
*/
public static class SfLocalDateTimeModule extends SimpleModule {
public SfLocalDateTimeModule() {
super(PackageVersion.VERSION);
// this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
/*对LocalDateTime类型 使用自定义序列化规则*/
this.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
this.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
this.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
// this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
/*对LocalDateTime类型 使用自定义反序列化规则*/
this.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
this.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
this.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
}
}
/**
* LocalDateTime 序列化 --> 时间戳
*/
public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
if (value != null) {
long timestamp = value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
gen.writeNumber(timestamp);
}
}
}
/**
* LocalDateTime 反序列化
* 支持格式:
* yyyy/MM/dd HH:mm:ss
* yyyy-MM-dd HH:mm:ss
* yyyyMMddHHmmss
*/
public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext)
throws IOException {
return LocalDateTimeUtil.parseStrToDate(p.getValueAsString(), LocalDateTime.class);
}
}
}
package xyz.zq.sf.common.core.config;
import cn.hutool.core.date.DatePattern;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.Parser;
import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import xyz.zq.sf.common.core.util.LocalDateTimeUtil;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
import static org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type.SERVLET;
/**
* Web Mvc配置
*
* @author hzq
* @date 2021-01-27 16:13
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = SERVLET)
public class WebMvcConfiguration implements WebMvcConfigurer {
/**
* @param registry 格式器注册表
*/
@Override
public void addFormatters(FormatterRegistry registry) {
setDateTimeFormatterRegistrar(registry);
}
/**
* 配置日期时间格式注册器
* 对所有以表单方式提交的日期类型进行转换
* Content-type:form-data、urlEncode
*
* @param registry 格式器注册表
*/
protected void setDateTimeFormatterRegistrar(FormatterRegistry registry) {
/*日期时间格式注册器*/
DateTimeFormatterRegistrar tfr = new DateTimeFormatterRegistrar();
tfr.setTimeFormatter(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN));
tfr.setDateFormatter(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN));
tfr.registerFormatters(registry);
/*Str To Date解析器*/
registry.addParser(new StrToDateParser());
/*Str到本地日期时间解析器*/
registry.addParser(new StrToLocalDateTimeParser());
}
/**
* String to Date
* 字符串解析成日期类型
*/
public static class StrToDateParser implements Parser<Date> {
@Override
public Date parse(String text, Locale locale) {
return LocalDateTimeUtil.parseStrToDate(text, Date.class);
}
}
/**
* String to LocalDateTime
* 字符串解析成日期类型
*/
public static class StrToLocalDateTimeParser implements Parser<LocalDateTime> {
@Override
public LocalDateTime parse(String text, Locale locale) {
return LocalDateTimeUtil.parseStrToDate(text, LocalDateTime.class);
}
}
}
package xyz.zq.sf.common.core.util;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import lombok.experimental.UtilityClass;
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 java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* 当地日期时间工具类
*
* @author hzq
* @date 2021-01-27 13:15
*/
@UtilityClass
public class LocalDateTimeUtil {
public final static Map<String, Pattern> patternRegexMap = new HashMap<>();
/*匹配全数字*/
public final static Pattern timeStampPattern = Pattern.compile("[0-9]*");
static {
/*ios 时间格式*/
patternRegexMap.put("yyyy/MM/dd HH:mm:ss", Pattern.compile("\\d{4}/\\d{1,2}/\\d{1,2}(\\s\\d{1,2}:\\d{1,2}:\\d{1,2})?"));
/*android 时间格式*/
patternRegexMap.put("yyyy-MM-dd HH:mm:ss", Pattern.compile("^(\\d{4})-([0-1]\\d)-([0-3]\\d)\\s([0-5]\\d):([0-5]\\d):([0-5]\\d)$"));
/*时间戳格式*/
patternRegexMap.put("yyyyMMddHHmmss", Pattern.compile("^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229))([0-1]?[0-9]|2[0-3])([0-5][0-9])([0-5][0-9])$"));
}
/**
* 解析
* String --> Date
* String --> LocalDateTime
* 字符串解析成日期类型
*
* @param str 字符串类型时间
* @return Class<T>
*/
@SuppressWarnings("unchecked")
public static <T> T parseStrToDate(String str, Class<T> requiredType) {
if (StrUtil.isBlank(str)) return null;
/*
* ios 格式
* android 格式
* 时间戳 格式
*/
for (Map.Entry<String, Pattern> next : LocalDateTimeUtil.patternRegexMap.entrySet()) {
boolean matches = ReUtil.isMatch(next.getValue(), str);
if (matches) {
if (requiredType.isAssignableFrom(Date.class)) {
try {
return ((T) new SimpleDateFormat(next.getKey()).parse(str));
} catch (ParseException ignore) {
}
}
if (requiredType.isAssignableFrom(LocalDateTime.class)) {
return ((T) LocalDateTime.parse(str, DateTimeFormatter.ofPattern(next.getKey())));
}
}
}
/*
* 全数字 当成时间戳来解析
*/
boolean match = ReUtil.isMatch(LocalDateTimeUtil.timeStampPattern, str);
if (match) {
if (requiredType.isAssignableFrom(Date.class)) {
return ((T) new Date(Long.parseLong(str)));
}
if (requiredType.isAssignableFrom(LocalDateTime.class)) {
return ((T) LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(str)), ZoneId.systemDefault()));
}
}
return null;
}
}