Commit 441fe1872099bab8ac1e999e484ece0b777fa4cf

Authored by YunaiV
1 parent 005d64aa

feat:【framework 框架】优化 jackson 的初始化

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 }