|
@@ -0,0 +1,302 @@
|
|
|
+package com.yonge.cooleshow.biz.dal.config.jackson;
|
|
|
+
|
|
|
+import com.fasterxml.jackson.core.JsonGenerator;
|
|
|
+import com.fasterxml.jackson.core.JsonParser;
|
|
|
+import com.fasterxml.jackson.databind.BeanProperty;
|
|
|
+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.SerializerProvider;
|
|
|
+import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
|
|
|
+import com.fasterxml.jackson.databind.deser.std.DateDeserializers;
|
|
|
+import com.fasterxml.jackson.databind.module.SimpleModule;
|
|
|
+import com.fasterxml.jackson.databind.ser.std.DateSerializer;
|
|
|
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|
|
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
|
|
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
|
|
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
|
|
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
|
|
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
|
|
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
|
|
+import com.yonge.cooleshow.common.config.EnumConverterFactory;
|
|
|
+import com.yonge.toolset.base.enums.BaseEnum;
|
|
|
+import lombok.Data;
|
|
|
+import lombok.EqualsAndHashCode;
|
|
|
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
|
|
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|
|
+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 org.springframework.core.convert.converter.Converter;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.BigInteger;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.text.DecimalFormat;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.LocalTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.TimeZone;
|
|
|
+
|
|
|
+/**
|
|
|
+ * JSON LocalDateTime 序列化、反序列化配置
|
|
|
+ */
|
|
|
+@Configuration
|
|
|
+@ConditionalOnClass(ObjectMapper.class)
|
|
|
+@AutoConfigureBefore(JacksonAutoConfiguration.class)
|
|
|
+public class JacksonConfig {
|
|
|
+
|
|
|
+ public static final String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; // 时间格式
|
|
|
+ public static final String NORM_DATE_PATTERN = "yyyy-MM-dd";
|
|
|
+ public static final String NORM_TIME_PATTERN = "HH:mm:ss";
|
|
|
+ //public static final String NORM_TIME_ZONE = "GMT+8"; // 时区设置
|
|
|
+ /**
|
|
|
+ * 时区配置
|
|
|
+ */
|
|
|
+ @Bean
|
|
|
+ public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
|
|
+ return builder -> {
|
|
|
+
|
|
|
+ // 配置Date的格式化
|
|
|
+ builder.locale(Locale.CHINA);
|
|
|
+ builder.timeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
|
|
+ builder.simpleDateFormat(NORM_DATETIME_PATTERN);
|
|
|
+
|
|
|
+ // 配置Jackson转换配置
|
|
|
+ //builder.configure(new JacksonObjectMapper());
|
|
|
+
|
|
|
+ //builder.serializationInclusion(JsonInclude.Include.USE_DEFAULTS);
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
|
|
|
+ * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
|
|
|
+ * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
|
|
|
+ */
|
|
|
+ public static class JacksonObjectMapper extends ObjectMapper {
|
|
|
+
|
|
|
+ public JacksonObjectMapper() {
|
|
|
+ super();
|
|
|
+ //反序列化的时候如果多了其他属性,不抛出异常
|
|
|
+ this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
|
|
+ //.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
|
|
|
+ //不注释,会导致swagger报错
|
|
|
+ //.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL)
|
|
|
+ //关闭日期序列化为时间戳的功能
|
|
|
+ //.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
|
|
+ //关闭序列化的时候没有为属性找到getter方法,报错
|
|
|
+ //.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
|
|
|
+ //关闭反序列化的时候,没有找到属性的setter报错
|
|
|
+ //.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
|
|
+ //序列化的时候序列对象的所有属性
|
|
|
+ //.setSerializationInclusion(JsonInclude.Include.ALWAYS)
|
|
|
+ //如果是空对象的时候,不抛异常
|
|
|
+ //.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
|
|
|
+ //反序列化时,属性不存在的兼容处理
|
|
|
+ //.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
|
|
+ .setDateFormat(new SimpleDateFormat(NORM_DATETIME_PATTERN, Locale.SIMPLIFIED_CHINESE))
|
|
|
+ .setLocale(Locale.CHINA)
|
|
|
+ .setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
|
|
+
|
|
|
+ SimpleModule simpleModule = new SimpleModule()
|
|
|
+ // 时间对象反序列化
|
|
|
+ .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN)))
|
|
|
+ .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(NORM_DATE_PATTERN)))
|
|
|
+ .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(NORM_TIME_PATTERN)))
|
|
|
+ .addDeserializer(Date.class,new DateDeserializers.DateDeserializer(DateDeserializers.DateDeserializer.instance,
|
|
|
+ new SimpleDateFormat(NORM_DATETIME_PATTERN), NORM_DATETIME_PATTERN))
|
|
|
+
|
|
|
+ // 时间对象序列化
|
|
|
+ .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN)))
|
|
|
+ .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(NORM_DATE_PATTERN)))
|
|
|
+ .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(NORM_TIME_PATTERN)))
|
|
|
+ .addSerializer(Date.class, new DateSerializer(false, new SimpleDateFormat(NORM_DATETIME_PATTERN)))
|
|
|
+
|
|
|
+ // 枚举类序列化
|
|
|
+ .addDeserializer(Enum.class, new BaseEnumDeserializer())
|
|
|
+ .addSerializer(BaseEnum.class, new BaseEnumSerializer())
|
|
|
+
|
|
|
+ // Long对象转String
|
|
|
+ //.addSerializer(Float.class, new FloatJsonSerializer())
|
|
|
+ //.addSerializer(Float.TYPE, new FloatJsonSerializer())
|
|
|
+
|
|
|
+ .addSerializer(Long.class, ToStringSerializer.instance)
|
|
|
+ .addSerializer(Long.TYPE, ToStringSerializer.instance)
|
|
|
+
|
|
|
+ .addSerializer(BigDecimal.class, new BigDecimalJsonSerializer())
|
|
|
+ .addSerializer(BigInteger.class, ToStringSerializer.instance)
|
|
|
+
|
|
|
+ .addSerializer(Double.class, new DoubleJsonSerializer())
|
|
|
+ .addSerializer(Double.TYPE, new DoubleJsonSerializer());
|
|
|
+
|
|
|
+ //注册功能模块 例如,可以添加自定义序列化器和反序列化器
|
|
|
+ this.registerModule(simpleModule);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Double精度处理
|
|
|
+ * #@JsonSerialize(using = JacksonConvertConfig.DoubleJsonSerializer.class)
|
|
|
+ */
|
|
|
+ public static class DoubleJsonSerializer extends JsonSerializer<Double> {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void serialize(Double arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
|
|
|
+ if(arg0 != null) {
|
|
|
+ getJsonConvertValue(arg1, new BigDecimal(String.valueOf(arg0)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * JSON数据转换
|
|
|
+ * @param arg1 JsonGenerator
|
|
|
+ * @param bigDecimal BigDecimal
|
|
|
+ * @throws IOException IOException
|
|
|
+ */
|
|
|
+ private static void getJsonConvertValue(JsonGenerator arg1, BigDecimal bigDecimal) throws IOException {
|
|
|
+
|
|
|
+ // 原本这里是 ##.00 ,带来的问题是如果数据库数据为0.00返回“ .00 “经评论指正,改为0.00
|
|
|
+ DecimalFormat decimalFormat = new DecimalFormat("#.00");
|
|
|
+
|
|
|
+ decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
|
|
|
+ //四舍五入。需要将数据转成bigDecimal, 否则会存在经度丢失问题
|
|
|
+ String format = decimalFormat.format(bigDecimal);
|
|
|
+
|
|
|
+ arg1.writeNumber(new BigDecimal(format));//返回数字格式
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * BigDecimal精度处理
|
|
|
+ * #@JsonSerialize(using = JacksonConvertConfig.BigDecimalJsonSerializer.class)
|
|
|
+ */
|
|
|
+ public static class BigDecimalJsonSerializer extends JsonSerializer<BigDecimal> {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void serialize(BigDecimal arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
|
|
|
+ if(arg0 != null) {
|
|
|
+ getJsonConvertValue(arg1, arg0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Float精度处理
|
|
|
+ * #@JsonSerialize(using = JacksonConvertConfig.FloatJsonSerializer.class)
|
|
|
+ */
|
|
|
+ public static class FloatJsonSerializer extends JsonSerializer<Float> {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void serialize(Float arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
|
|
|
+ if(arg0 != null) {
|
|
|
+ getJsonConvertValue(arg1, new BigDecimal(String.valueOf(arg0)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 枚举类反序列化
|
|
|
+ */
|
|
|
+ @Data
|
|
|
+ @EqualsAndHashCode(callSuper = true)
|
|
|
+ public static class BaseEnumDeserializer extends JsonDeserializer<Enum<?>> implements ContextualDeserializer {
|
|
|
+
|
|
|
+ private Class<?> target;
|
|
|
+
|
|
|
+ @SuppressWarnings("all")
|
|
|
+ @Override
|
|
|
+ public Enum<?> deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
|
|
|
+ if (!StringUtils.hasText(jsonParser.getText())) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (BaseEnum.class.isAssignableFrom(target)) {
|
|
|
+ return (Enum<?>) EnumConverterFactory.getEnum((Class) target, jsonParser.getText());
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param ctx DeserializationContext
|
|
|
+ * @param property BeanProperty
|
|
|
+ * @return JsonDeserializer
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public JsonDeserializer<?> createContextual(DeserializationContext ctx, BeanProperty property) {
|
|
|
+ Class<?> rawCls = ctx.getContextualType().getRawClass();
|
|
|
+ BaseEnumDeserializer enumDeserializer = new BaseEnumDeserializer();
|
|
|
+ enumDeserializer.setTarget(rawCls);
|
|
|
+ return enumDeserializer;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 枚举类序列化
|
|
|
+ */
|
|
|
+ public static class BaseEnumSerializer extends JsonSerializer<BaseEnum> {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void serialize(BaseEnum enums, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
|
|
|
+
|
|
|
+ if (enums.getCode() instanceof Integer) {
|
|
|
+ // 返回整形
|
|
|
+ jsonGenerator.writeNumber(Integer.parseInt(String.valueOf(enums.getCode())));
|
|
|
+ } else {
|
|
|
+ // 返回字符串
|
|
|
+ jsonGenerator.writeString(String.valueOf(enums.getCode()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 字符串格式转日期
|
|
|
+ */
|
|
|
+ public static class CustomStringDateConverter implements Converter<String, Date> {
|
|
|
+ private static final String dateFormat = "yyyy-MM-dd HH:mm:ss";
|
|
|
+ private static final String shortDateFormat = "yyyy-MM-dd";
|
|
|
+ private static final String dateFormat2 = "yyyy/MM/dd HH:mm:ss";
|
|
|
+ private static final String shortDateFormat2 = "yyyy/MM/dd";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Date convert(String source) {
|
|
|
+ if (org.apache.commons.lang3.StringUtils.isBlank(source)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ source = source.trim();
|
|
|
+ try {
|
|
|
+ SimpleDateFormat formatter;
|
|
|
+ if (source.contains("-")) {
|
|
|
+ if (source.contains(":")) {
|
|
|
+ formatter = new SimpleDateFormat(dateFormat);
|
|
|
+ } else {
|
|
|
+ formatter = new SimpleDateFormat(shortDateFormat);
|
|
|
+ }
|
|
|
+ return formatter.parse(source);
|
|
|
+ } else if (source.contains("/")) {
|
|
|
+ if (source.contains(":")) {
|
|
|
+ formatter = new SimpleDateFormat(dateFormat2);
|
|
|
+ } else {
|
|
|
+ formatter = new SimpleDateFormat(shortDateFormat2);
|
|
|
+ }
|
|
|
+ return formatter.parse(source);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException(String.format("parser %s to Date fail", source));
|
|
|
+ }
|
|
|
+
|
|
|
+ throw new RuntimeException(String.format("parser %s to Date fail", source));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|