Commit 441fe1872099bab8ac1e999e484ece0b777fa4cf
1 parent
005d64aa
feat:【framework 框架】优化 jackson 的初始化
Showing
3 changed files
with
51 additions
and
25 deletions
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/db/TenantDatabaseInterceptor.java
| @@ -75,7 +75,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler { | @@ -75,7 +75,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler { | ||
| 75 | if (TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) { | 75 | if (TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) { |
| 76 | return false; | 76 | return false; |
| 77 | } | 77 | } |
| 78 | - // 如果添加了 @TenantIgnore 注解,显然也不忽略租户 | 78 | + // 如果添加了 @TenantIgnore 注解,则忽略租户 |
| 79 | TenantIgnore tenantIgnore = tableInfo.getEntityType().getAnnotation(TenantIgnore.class); | 79 | TenantIgnore tenantIgnore = tableInfo.getEntityType().getAnnotation(TenantIgnore.class); |
| 80 | return tenantIgnore != null; | 80 | return tenantIgnore != null; |
| 81 | } | 81 | } |
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java
| 1 | package cn.iocoder.yudao.framework.jackson.config; | 1 | package cn.iocoder.yudao.framework.jackson.config; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.collection.CollUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 3 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 5 | import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer; | 4 | import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer; |
| 6 | import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer; | 5 | import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer; |
| 7 | import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer; | 6 | import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer; |
| 7 | +import com.fasterxml.jackson.databind.Module; | ||
| 8 | import com.fasterxml.jackson.databind.ObjectMapper; | 8 | import com.fasterxml.jackson.databind.ObjectMapper; |
| 9 | import com.fasterxml.jackson.databind.module.SimpleModule; | 9 | import com.fasterxml.jackson.databind.module.SimpleModule; |
| 10 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; | 10 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; |
| @@ -13,39 +13,65 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; | @@ -13,39 +13,65 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; | ||
| 13 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; | 13 | import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; |
| 14 | import lombok.extern.slf4j.Slf4j; | 14 | import lombok.extern.slf4j.Slf4j; |
| 15 | import org.springframework.boot.autoconfigure.AutoConfiguration; | 15 | import org.springframework.boot.autoconfigure.AutoConfiguration; |
| 16 | +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; | ||
| 17 | +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; | ||
| 16 | import org.springframework.context.annotation.Bean; | 18 | import org.springframework.context.annotation.Bean; |
| 17 | 19 | ||
| 18 | import java.time.LocalDate; | 20 | import java.time.LocalDate; |
| 19 | import java.time.LocalDateTime; | 21 | import java.time.LocalDateTime; |
| 20 | import java.time.LocalTime; | 22 | import java.time.LocalTime; |
| 21 | -import java.util.List; | ||
| 22 | 23 | ||
| 23 | -@AutoConfiguration | 24 | +@AutoConfiguration(after = JacksonAutoConfiguration.class) |
| 24 | @Slf4j | 25 | @Slf4j |
| 25 | public class YudaoJacksonAutoConfiguration { | 26 | public class YudaoJacksonAutoConfiguration { |
| 26 | 27 | ||
| 28 | + /** | ||
| 29 | + * 从 Builder 源头定制(关键:使用 *ByType,避免 handledType 要求) | ||
| 30 | + */ | ||
| 27 | @Bean | 31 | @Bean |
| 28 | - @SuppressWarnings("InstantiationOfUtilityClass") | ||
| 29 | - public JsonUtils jsonUtils(List<ObjectMapper> objectMappers) { | ||
| 30 | - // 1.1 创建 SimpleModule 对象 | ||
| 31 | - SimpleModule simpleModule = new SimpleModule(); | ||
| 32 | - simpleModule | ||
| 33 | - // 新增 Long 类型序列化规则,数值超过 2^53-1,在 JS 会出现精度丢失问题,因此 Long 自动序列化为字符串类型 | ||
| 34 | - .addSerializer(Long.class, NumberSerializer.INSTANCE) | ||
| 35 | - .addSerializer(Long.TYPE, NumberSerializer.INSTANCE) | ||
| 36 | - .addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE) | ||
| 37 | - .addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE) | ||
| 38 | - .addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE) | ||
| 39 | - .addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE) | ||
| 40 | - // 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳 | ||
| 41 | - .addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) | ||
| 42 | - .addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); | ||
| 43 | - // 1.2 注册到 objectMapper | ||
| 44 | - objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule)); | 32 | + public Jackson2ObjectMapperBuilderCustomizer ldtEpochMillisCustomizer() { |
| 33 | + return builder -> builder | ||
| 34 | + // Long -> Number | ||
| 35 | + .serializerByType(Long.class, NumberSerializer.INSTANCE) | ||
| 36 | + .serializerByType(Long.TYPE, NumberSerializer.INSTANCE) | ||
| 37 | + // LocalDate / LocalTime | ||
| 38 | + .serializerByType(LocalDate.class, LocalDateSerializer.INSTANCE) | ||
| 39 | + .deserializerByType(LocalDate.class, LocalDateDeserializer.INSTANCE) | ||
| 40 | + .serializerByType(LocalTime.class, LocalTimeSerializer.INSTANCE) | ||
| 41 | + .deserializerByType(LocalTime.class, LocalTimeDeserializer.INSTANCE) | ||
| 42 | + // LocalDateTime < - > EpochMillis | ||
| 43 | + .serializerByType(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) | ||
| 44 | + .deserializerByType(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); | ||
| 45 | + } | ||
| 45 | 46 | ||
| 46 | - // 2. 设置 objectMapper 到 JsonUtils | ||
| 47 | - JsonUtils.init(CollUtil.getFirst(objectMappers)); | ||
| 48 | - log.info("[init][初始化 JsonUtils 成功]"); | 47 | + /** |
| 48 | + * 以 Bean 形式暴露 Module(Boot 会自动注册到所有 ObjectMapper) | ||
| 49 | + */ | ||
| 50 | + @Bean | ||
| 51 | + public Module timestampSupportModuleBean() { | ||
| 52 | + SimpleModule m = new SimpleModule("TimestampSupportModule"); | ||
| 53 | + // Long -> Number,避免前端精度丢失 | ||
| 54 | + m.addSerializer(Long.class, NumberSerializer.INSTANCE); | ||
| 55 | + m.addSerializer(Long.TYPE, NumberSerializer.INSTANCE); | ||
| 56 | + // LocalDate / LocalTime | ||
| 57 | + m.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE); | ||
| 58 | + m.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE); | ||
| 59 | + m.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE); | ||
| 60 | + m.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE); | ||
| 61 | + // LocalDateTime < - > EpochMillis | ||
| 62 | + m.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE); | ||
| 63 | + m.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); | ||
| 64 | + return m; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * 初始化全局 JsonUtils,直接使用主 ObjectMapper | ||
| 69 | + */ | ||
| 70 | + @Bean | ||
| 71 | + @SuppressWarnings("InstantiationOfUtilityClass") | ||
| 72 | + public JsonUtils jsonUtils(ObjectMapper objectMapper) { | ||
| 73 | + JsonUtils.init(objectMapper); | ||
| 74 | + log.debug("[init][初始化 JsonUtils 成功]"); | ||
| 49 | return new JsonUtils(); | 75 | return new JsonUtils(); |
| 50 | } | 76 | } |
| 51 | 77 |
yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
| @@ -166,7 +166,7 @@ public class CouponServiceImpl implements CouponService { | @@ -166,7 +166,7 @@ public class CouponServiceImpl implements CouponService { | ||
| 166 | public void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId) { | 166 | public void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId) { |
| 167 | // 循环收回 | 167 | // 循环收回 |
| 168 | for (Long couponId : giveCouponIds) { | 168 | for (Long couponId : giveCouponIds) { |
| 169 | - // couponId为空或0则跳过 | 169 | + // couponId 为空或 0 则跳过 |
| 170 | if (null == couponId || couponId <= 0) { | 170 | if (null == couponId || couponId <= 0) { |
| 171 | continue; | 171 | continue; |
| 172 | } | 172 | } |