新增 long 集合类型的 string 转换

This commit is contained in:
chenbowen
2025-11-24 19:18:23 +08:00
parent 77c46acf9e
commit 65b99740c1
4 changed files with 134 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
package com.zt.plat.framework.common.util.json.databind;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
/**
* Long / long 数组序列化器,统一按字符串输出以规避 JS 精度问题。
*/
public class LongArraySerializer extends StdSerializer<Object> {
public static final LongArraySerializer INSTANCE = new LongArraySerializer();
private LongArraySerializer() {
super(Object.class);
}
@Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeStartArray();
if (value instanceof long[]) {
long[] array = (long[]) value;
for (long element : array) {
// 原生 long 必定有值,直接走 NumberSerializer
NumberSerializer.INSTANCE.serialize(element, gen, provider);
}
gen.writeEndArray();
return;
}
Long[] array = (Long[]) value;
for (Long element : array) {
if (element == null) {
provider.defaultSerializeNull(gen);
continue;
}
NumberSerializer.INSTANCE.serialize(element, gen, provider);
}
gen.writeEndArray();
}
}

View File

@@ -0,0 +1,37 @@
package com.zt.plat.framework.common.util.json.databind;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.databind.type.TypeFactory;
import java.io.IOException;
import java.util.Collection;
/**
* 将 {@link Collection} 中的 Long 元素序列化成字符串,避免 JavaScript 精度问题。
*/
public class LongCollectionSerializer extends StdSerializer<Collection<?>> {
public static final LongCollectionSerializer INSTANCE = new LongCollectionSerializer();
private LongCollectionSerializer() {
super(TypeFactory.defaultInstance().constructCollectionType(Collection.class, Object.class));
}
@Override
public void serialize(Collection<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
// 传入集合本身与元素数量,方便 Jackson 合理推测数组边界
gen.writeStartArray(value, value.size());
for (Object element : value) {
if (element == null) {
// 允许集合中存在 null保持 Jackson 默认的 null 序列化行为
provider.defaultSerializeNull(gen);
continue;
}
// 所有 Long/long 元素统一走 NumberSerializer保证前端精度
NumberSerializer.INSTANCE.serialize((Number) element, gen, provider);
}
gen.writeEndArray();
}
}

View File

@@ -0,0 +1,52 @@
package com.zt.plat.framework.common.util.json.databind;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.databind.type.ArrayType;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.databind.type.CollectionLikeType;
import com.fasterxml.jackson.databind.JavaType;
/**
* 针对 Long 相关集合、数组的序列化增强,确保统一走 Long 的自定义序列化逻辑。
*/
public class LongTypeSerializerModifier extends BeanSerializerModifier {
@Override
public JsonSerializer<?> modifyCollectionSerializer(SerializationConfig config, CollectionType valueType,
BeanDescription beanDesc, JsonSerializer<?> serializer) {
// List、Set 等容器若包含 Long则切换到 LongCollectionSerializer
return needsLongCollectionSerializer(valueType.getContentType()) ? LongCollectionSerializer.INSTANCE : serializer;
}
@Override
public JsonSerializer<?> modifyCollectionLikeSerializer(SerializationConfig config, CollectionLikeType valueType,
BeanDescription beanDesc, JsonSerializer<?> serializer) {
// 处理 CollectionLike如 Page、Optional 等)中的 Long 元素
return needsLongCollectionSerializer(valueType.getContentType()) ? LongCollectionSerializer.INSTANCE : serializer;
}
@Override
public JsonSerializer<?> modifyArraySerializer(SerializationConfig config, ArrayType valueType,
BeanDescription beanDesc, JsonSerializer<?> serializer) {
// 针对 long[]、Long[] 两种数组使用统一的数组序列化器
Class<?> rawClass = valueType.getRawClass();
if (long[].class.equals(rawClass)) {
return LongArraySerializer.INSTANCE;
}
if (Long[].class.equals(rawClass)) {
return LongArraySerializer.INSTANCE;
}
return serializer;
}
private boolean needsLongCollectionSerializer(JavaType contentType) {
if (contentType == null) {
return false;
}
Class<?> rawClass = contentType.getRawClass();
return Long.class.equals(rawClass) || Long.TYPE.equals(rawClass);
}
}

View File

@@ -2,6 +2,7 @@ package com.zt.plat.gateway.jackson;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.zt.plat.framework.common.util.json.JsonUtils; import com.zt.plat.framework.common.util.json.JsonUtils;
import com.zt.plat.framework.common.util.json.databind.LongTypeSerializerModifier;
import com.zt.plat.framework.common.util.json.databind.NumberSerializer; import com.zt.plat.framework.common.util.json.databind.NumberSerializer;
import com.zt.plat.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer; import com.zt.plat.framework.common.util.json.databind.TimestampLocalDateTimeDeserializer;
import com.zt.plat.framework.common.util.json.databind.TimestampLocalDateTimeSerializer; import com.zt.plat.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
@@ -39,6 +40,7 @@ public class JacksonAutoConfiguration {
// 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳 // 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳
.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE) .addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE)
.addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE); .addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);
simpleModule.setSerializerModifier(new LongTypeSerializerModifier());
// 1.2 注册到 objectMapper // 1.2 注册到 objectMapper
objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule)); objectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule));