From 811abe87950ceb6d89787a03c02f653f0544745a Mon Sep 17 00:00:00 2001 From: Ponfee Date: Sat, 27 Jan 2024 21:34:31 +0800 Subject: [PATCH] json --- .../admin/DisjobAdminConfiguration.java | 33 +----- .../spring/EnableJacksonDateConfigurer.java | 39 ++----- .../cn/ponfee/disjob/common/util/Jsons.java | 103 +++++++++++------- 3 files changed, 77 insertions(+), 98 deletions(-) diff --git a/disjob-admin/ruoyi-disjob/src/main/java/cn/ponfee/disjob/admin/DisjobAdminConfiguration.java b/disjob-admin/ruoyi-disjob/src/main/java/cn/ponfee/disjob/admin/DisjobAdminConfiguration.java index 25aee1240..9af8c9bed 100644 --- a/disjob-admin/ruoyi-disjob/src/main/java/cn/ponfee/disjob/admin/DisjobAdminConfiguration.java +++ b/disjob-admin/ruoyi-disjob/src/main/java/cn/ponfee/disjob/admin/DisjobAdminConfiguration.java @@ -16,20 +16,12 @@ import cn.ponfee.disjob.id.snowflake.db.DbDistributedSnowflake; import cn.ponfee.disjob.supervisor.configuration.EnableSupervisor; import cn.ponfee.disjob.worker.configuration.EnableWorker; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; 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.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.lang.Nullable; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import java.math.BigInteger; import static cn.ponfee.disjob.supervisor.dao.SupervisorDataSourceConfig.JDBC_TEMPLATE_SPRING_BEAN_NAME; @@ -41,30 +33,17 @@ @Configuration @ComponentScan("cn.ponfee.disjob.test.handler") @EnableJacksonDateConfigurer // 解决日期反序列化报错的问题 -@EnableSupervisor // disjob-admin必须启用Supervisor角色,即:必须加@EnableSupervisor注解 -@EnableWorker // 若要取消worker角色可去掉@EnableWorker注解 -public class DisjobAdminConfiguration implements WebMvcConfigurer { - - public DisjobAdminConfiguration(@Nullable ObjectMapper objectMapper) { - if (objectMapper == null) { - throw new Error("Not found jackson object mapper in spring container."); - } - objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); - - SimpleModule simpleModule = new SimpleModule(); - // 返回给端上浏览器JavaScript Number数值过大时会有问题:Number.MAX_SAFE_INTEGER = 9007199254740991 - // 当数值大于`9007199254740991`时就有可能会丢失精度:1234567891011121314 -> 1234567891011121400 - simpleModule.addSerializer(Long.class, ToStringSerializer.instance); - simpleModule.addSerializer(long.class, ToStringSerializer.instance); - simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance); - objectMapper.registerModule(simpleModule); - } +@EnableSupervisor // disjob-admin必须启用Supervisor角色,即:必须加@EnableSupervisor注解 +@EnableWorker // 若要取消worker角色可去掉@EnableWorker注解 +public class DisjobAdminConfiguration { @Bean public IdGenerator idGenerator(@Qualifier(JDBC_TEMPLATE_SPRING_BEAN_NAME) JdbcTemplate jdbcTemplate, @Value("${" + JobConstants.SPRING_WEB_SERVER_PORT + "}") int port, @Value("${" + JobConstants.DISJOB_BOUND_SERVER_HOST + ":}") String boundHost) { - return new DbDistributedSnowflake(jdbcTemplate, JobConstants.DISJOB_KEY_PREFIX, JobUtils.getLocalHost(boundHost) + Char.COLON + port); + // serverTag = host:port + String serverTag = JobUtils.getLocalHost(boundHost) + Char.COLON + port; + return new DbDistributedSnowflake(jdbcTemplate, JobConstants.DISJOB_KEY_PREFIX, serverTag); } } diff --git a/disjob-common/src/main/java/cn/ponfee/disjob/common/spring/EnableJacksonDateConfigurer.java b/disjob-common/src/main/java/cn/ponfee/disjob/common/spring/EnableJacksonDateConfigurer.java index aaad8a34c..c4136456d 100644 --- a/disjob-common/src/main/java/cn/ponfee/disjob/common/spring/EnableJacksonDateConfigurer.java +++ b/disjob-common/src/main/java/cn/ponfee/disjob/common/spring/EnableJacksonDateConfigurer.java @@ -8,24 +8,15 @@ package cn.ponfee.disjob.common.spring; -import cn.ponfee.disjob.common.date.*; +import cn.ponfee.disjob.common.date.JavaUtilDateFormat; +import cn.ponfee.disjob.common.util.Jsons; +import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -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.LocalDateTimeSerializer; -import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import org.springframework.context.annotation.Import; import org.springframework.lang.Nullable; import java.lang.annotation.*; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.format.DateTimeFormatter; -import java.util.Date; /** * Enable object mapper configurer @@ -45,25 +36,11 @@ public ObjectMapperConfigurer(@Nullable ObjectMapper objectMapper) { return; } + objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); objectMapper.setDateFormat(JavaUtilDateFormat.DEFAULT); - - SimpleModule module = new SimpleModule(); - module.addSerializer(Date.class, JacksonDate.INSTANCE.serializer()); - module.addDeserializer(Date.class, JacksonDate.INSTANCE.deserializer()); - objectMapper.registerModule(module); - - // java.time.LocalDateTime - DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(Dates.DATE_PATTERN); - DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); - - JavaTimeModule javaTimeModule = new JavaTimeModule(); - javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(LocalDateTimeFormat.PATTERN_11)); - javaTimeModule.addDeserializer(LocalDateTime.class, CustomLocalDateTimeDeserializer.INSTANCE); - javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(dateFormatter)); - javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter)); - javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter)); - javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter)); - objectMapper.registerModule(javaTimeModule); + Jsons.registerSimpleModule(objectMapper); + Jsons.registerJavaTimeModule(objectMapper); + objectMapper.registerModule(new Jdk8Module()); } } diff --git a/disjob-common/src/main/java/cn/ponfee/disjob/common/util/Jsons.java b/disjob-common/src/main/java/cn/ponfee/disjob/common/util/Jsons.java index be59a8d76..82a365377 100644 --- a/disjob-common/src/main/java/cn/ponfee/disjob/common/util/Jsons.java +++ b/disjob-common/src/main/java/cn/ponfee/disjob/common/util/Jsons.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; @@ -191,6 +192,7 @@ public T parse(byte[] json, TypeReference type) { } // ----------------------------------------------------static methods + public static String toJson(Object target) { return NORMAL.string(target); } @@ -204,18 +206,18 @@ public static Object[] parseArray(String body, Class... types) { return null; } - ObjectMapper mapper = NORMAL.mapper; - JsonNode rootNode = readTree(mapper, body); + ObjectMapper objectMapper = NORMAL.mapper; + JsonNode rootNode = readTree(objectMapper, body); Assert.isTrue(rootNode.isArray(), "Not array json data."); ArrayNode arrayNode = (ArrayNode) rootNode; if (types.length == 1 && arrayNode.size() > 1) { - return new Object[]{parse(mapper, arrayNode, types[0])}; + return new Object[]{parse(objectMapper, arrayNode, types[0])}; } Object[] result = new Object[types.length]; for (int i = 0; i < types.length; i++) { - result[i] = parse(mapper, arrayNode.get(i), types[i]); + result[i] = parse(objectMapper, arrayNode.get(i), types[i]); } return result; } @@ -234,8 +236,8 @@ public static Object[] parseMethodArgs(String body, Method method) { return null; } - ObjectMapper mapper = NORMAL.mapper; - JsonNode rootNode = readTree(mapper, body); + ObjectMapper objectMapper = NORMAL.mapper; + JsonNode rootNode = readTree(objectMapper, body); if (rootNode.isArray()) { ArrayNode arrayNode = (ArrayNode) rootNode; @@ -243,7 +245,7 @@ public static Object[] parseMethodArgs(String body, Method method) { // ["a", "b"] -> method(Object[] arg) -> arg=["a", "b"] // [["a"], ["b"]] -> method(Object[] arg) -> arg=[["a"], ["b"]] if (argumentCount == 1 && arrayNode.size() > 1) { - return new Object[]{parse(mapper, arrayNode, genericArgumentTypes[0])}; + return new Object[]{parse(objectMapper, arrayNode, genericArgumentTypes[0])}; } // 其它情况,在调用方将参数(requestParameters)用数组包一层:new Object[]{ arg-1, arg-2, ..., arg-n } @@ -257,12 +259,12 @@ public static Object[] parseMethodArgs(String body, Method method) { Object[] methodArguments = new Object[argumentCount]; for (int i = 0; i < argumentCount; i++) { - methodArguments[i] = parse(mapper, arrayNode.get(i), genericArgumentTypes[i]); + methodArguments[i] = parse(objectMapper, arrayNode.get(i), genericArgumentTypes[i]); } return methodArguments; } else { Assert.isTrue(argumentCount == 1, "Single object request parameter not support multiple arguments method."); - return new Object[]{parse(mapper, rootNode, genericArgumentTypes[0])}; + return new Object[]{parse(objectMapper, rootNode, genericArgumentTypes[0])}; } } @@ -318,44 +320,66 @@ public static ObjectMapper createObjectMapper(JsonInclude.Include include) { JsonFactory jsonFactory = new JsonFactoryBuilder() .disable(JsonFactory.Feature.INTERN_FIELD_NAMES) .build(); - ObjectMapper mapper = new ObjectMapper(jsonFactory); + ObjectMapper objectMapper = new ObjectMapper(jsonFactory); // 设置序列化时的特性 if (include != null) { - mapper.setSerializationInclusion(include); + objectMapper.setSerializationInclusion(include); } - configObjectMapper(mapper); - return mapper; + configObjectMapper(objectMapper); + return objectMapper; } - public static void configObjectMapper(ObjectMapper mapper) { - // 1、Common config - mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 反序列化时忽略未知属性 - mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // Date不序列化为时间戳 - mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); // 解决报错:No serializer found for class XXX and no properties discovered to create BeanSerializer - mapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); // BigDecimal禁用科学计数格式输出,new BigDecimal("0.00000000000000001"): 1E-17 -> 0.00000000000000001 - mapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); // 禁止无双引号字段 - mapper.enable(JsonWriteFeature.QUOTE_FIELD_NAMES.mappedFeature()); // 字段加双引号 + public static void configObjectMapper(ObjectMapper objectMapper) { + // Common config + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 反序列化时忽略未知属性 + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); // Date不序列化为时间戳 + objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); // 解决报错:No serializer found for class XXX and no properties discovered to create BeanSerializer + objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); // BigDecimal禁用科学计数格式输出,new BigDecimal("0.00000000000000001"): 1E-17 -> 0.00000000000000001 + objectMapper.disable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); // 禁止无双引号字段 + objectMapper.enable(JsonWriteFeature.QUOTE_FIELD_NAMES.mappedFeature()); // 字段加双引号 - // 2、java.util.Date config + // java.util.Date config // java.util.Date:registerModule > JsonFormat(会使用setTimeZone) > setDateFormat(会使用setTimeZone) // 1)如果同时配置了setDateFormat和registerModule,则使用registerModule // 2)如果设置了setTimeZone,则会调用setDateFormat#setTimeZone(注:setTimeZone对registerModule无影响) // 3)如果实体字段使用了JsonFormat注解,则setDateFormat不生效(会使用jackson内置的格式化器,默认为0时区,此时要setTimeZone) // 4)JsonFormat注解对registerModule无影响(registerModule优先级最高) - mapper.setTimeZone(JavaUtilDateFormat.DEFAULT.getTimeZone()); // TimeZone.getDefault() - mapper.setDateFormat(JavaUtilDateFormat.DEFAULT); - //mapper.setConfig(mapper.getDeserializationConfig().with(mapper.getDateFormat())); - //mapper.setConfig(mapper.getSerializationConfig().with(mapper.getDateFormat())); - - // 3、java.util.Date module config - SimpleModule module = new SimpleModule(); - module.addSerializer(Date.class, JacksonDate.INSTANCE.serializer()); - module.addDeserializer(Date.class, JacksonDate.INSTANCE.deserializer()); - //module.addSerializer(Money.class, JacksonMoney.INSTANCE.serializer()); - //module.addDeserializer(Money.class, JacksonMoney.INSTANCE.deserializer()); - mapper.registerModule(module); - - // 4、java.time.LocalDateTime module config + objectMapper.setTimeZone(JavaUtilDateFormat.DEFAULT.getTimeZone()); // TimeZone.getDefault() + objectMapper.setDateFormat(JavaUtilDateFormat.DEFAULT); + //objectMapper.setConfig(mapper.getDeserializationConfig().with(mapper.getDateFormat())); + //objectMapper.setConfig(mapper.getSerializationConfig().with(mapper.getDateFormat())); + + // register module + registerSimpleModule(objectMapper); + registerJavaTimeModule(objectMapper); + objectMapper.registerModule(new Jdk8Module()); + + // Others config + //objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); + } + + public static void registerSimpleModule(ObjectMapper objectMapper) { + SimpleModule simpleModule = new SimpleModule(); + + // java.util.Date module config + simpleModule.addSerializer(Date.class, JacksonDate.INSTANCE.serializer()); + simpleModule.addDeserializer(Date.class, JacksonDate.INSTANCE.deserializer()); + + // 金额序列化 + //simpleModule.addSerializer(Money.class, JacksonMoney.INSTANCE.serializer()); + //simpleModule.addDeserializer(Money.class, JacksonMoney.INSTANCE.deserializer()); + + // 返回给端上浏览器JavaScript Number数值过大时会有问题:Number.MAX_SAFE_INTEGER = 9007199254740991 + // 当数值大于`9007199254740991`时就有可能会丢失精度:1234567891011121314 -> 1234567891011121400 + //simpleModule.addSerializer(Long.class, ToStringSerializer.instance); + //simpleModule.addSerializer(long.class, ToStringSerializer.instance); + //simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance); + + objectMapper.registerModule(simpleModule); + } + + public static void registerJavaTimeModule(ObjectMapper objectMapper) { + // java new time module config DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(Dates.DATE_PATTERN); DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); JavaTimeModule javaTimeModule = new JavaTimeModule(); @@ -365,12 +389,11 @@ public static void configObjectMapper(ObjectMapper mapper) { javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(dateFormatter)); javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(timeFormatter)); javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(timeFormatter)); - mapper.registerModule(javaTimeModule); - - // 5、Others config - //mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); + objectMapper.registerModule(javaTimeModule); } + // -----------------------------------------------------------------------private methods + private static JsonNode readTree(ObjectMapper mapper, String body) { try { return mapper.readTree(body);