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

This commit is contained in:
YunaiV 2025-08-24 16:03:39 +08:00
parent 005d64aae6
commit 441fe18720
3 changed files with 51 additions and 25 deletions

View File

@ -75,7 +75,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
if (TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) { if (TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) {
return false; return false;
} }
// 如果添加了 @TenantIgnore 注解显然也不忽略租户 // 如果添加了 @TenantIgnore 注解忽略租户
TenantIgnore tenantIgnore = tableInfo.getEntityType().getAnnotation(TenantIgnore.class); TenantIgnore tenantIgnore = tableInfo.getEntityType().getAnnotation(TenantIgnore.class);
return tenantIgnore != null; return tenantIgnore != null;
} }

View File

@ -1,10 +1,10 @@
package cn.iocoder.yudao.framework.jackson.config; package cn.iocoder.yudao.framework.jackson.config;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer; import cn.iocoder.yudao.framework.common.util.json.databind.NumberSerializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer; import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer; import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
@ -13,39 +13,65 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
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.Bean;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.List;
@AutoConfiguration @AutoConfiguration(after = JacksonAutoConfiguration.class)
@Slf4j @Slf4j
public class YudaoJacksonAutoConfiguration { public class YudaoJacksonAutoConfiguration {
/**
* Builder 源头定制关键使用 *ByType避免 handledType 要求
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer ldtEpochMillisCustomizer() {
return builder -> builder
// Long -> Number
.serializerByType(Long.class, NumberSerializer.INSTANCE)
.serializerByType(Long.TYPE, NumberSerializer.INSTANCE)
// LocalDate / LocalTime
.serializerByType(LocalDate.class, LocalDateSerializer.INSTANCE)
.deserializerByType(LocalDate.class, LocalDateDeserializer.INSTANCE)
.serializerByType(LocalTime.class, LocalTimeSerializer.INSTANCE)
.deserializerByType(LocalTime.class, LocalTimeDeserializer.INSTANCE)
// LocalDateTime < - > EpochMillis
.serializerByType(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.deserializerByType(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
}
/**
* Bean 形式暴露 ModuleBoot 会自动注册到所有 ObjectMapper
*/
@Bean
public Module timestampSupportModuleBean() {
SimpleModule m = new SimpleModule("TimestampSupportModule");
// Long -> Number避免前端精度丢失
m.addSerializer(Long.class, NumberSerializer.INSTANCE);
m.addSerializer(Long.TYPE, NumberSerializer.INSTANCE);
// LocalDate / LocalTime
m.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE);
m.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE);
m.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE);
m.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE);
// LocalDateTime < - > EpochMillis
m.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE);
m.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
return m;
}
/**
* 初始化全局 JsonUtils直接使用主 ObjectMapper
*/
@Bean @Bean
@SuppressWarnings("InstantiationOfUtilityClass") @SuppressWarnings("InstantiationOfUtilityClass")
public JsonUtils jsonUtils(List<ObjectMapper> objectMappers) { public JsonUtils jsonUtils(ObjectMapper objectMapper) {
// 1.1 创建 SimpleModule 对象 JsonUtils.init(objectMapper);
SimpleModule simpleModule = new SimpleModule(); log.debug("[init][初始化 JsonUtils 成功]");
simpleModule
// 新增 Long 类型序列化规则数值超过 2^53-1 JS 会出现精度丢失问题因此 Long 自动序列化为字符串类型
.addSerializer(Long.class, NumberSerializer.INSTANCE)
.addSerializer(Long.TYPE, NumberSerializer.INSTANCE)
.addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE)
.addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE)
.addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE)
.addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE)
// 新增 LocalDateTime 序列化反序列化规则使用 Long 时间戳
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
// 1.2 注册到 objectMapper
objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule));
// 2. 设置 objectMapper JsonUtils
JsonUtils.init(CollUtil.getFirst(objectMappers));
log.info("[init][初始化 JsonUtils 成功]");
return new JsonUtils(); return new JsonUtils();
} }

View File

@ -166,7 +166,7 @@ public class CouponServiceImpl implements CouponService {
public void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId) { public void invalidateCouponsByAdmin(List<Long> giveCouponIds, Long userId) {
// 循环收回 // 循环收回
for (Long couponId : giveCouponIds) { for (Long couponId : giveCouponIds) {
// couponId为空或0则跳过 // couponId 为空或 0 则跳过
if (null == couponId || couponId <= 0) { if (null == couponId || couponId <= 0) {
continue; continue;
} }