雪花算法 长整型精度损失、枚举类型转换配置
package com.school.information.config;
import cn.hutool.core.lang.ClassScanner;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.JSONLexer;
import com.alibaba.fastjson.parser.JSONToken;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializeWriter;
import com.alibaba.fastjson.serializer.ToStringSerializer;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.school.information.enums.BaseEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Slf4j
@Configuration
public class ServiceConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
//自定义配置...
List<MediaType> mediaTypes = getMediaType();
converter.setSupportedMediaTypes(mediaTypes);
SerializeConfig serializeConfig = SerializeConfig.getGlobalInstance();
ParserConfig parserConfig = ParserConfig.getGlobalInstance();
//以下几种类型解析时解析为string,避免精度丢失
serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
serializeConfig.put(Long.class, ToStringSerializer.instance);
serializeConfig.put(BigDecimal.class, ToStringSerializer.instance);
//获取枚举包下所有枚举类
Set<Class<?>> enumTypes = getEnumTypes();
//为枚举类配置序列化和反序列化方法,只要实现BaseEnum接口的枚举类都可以被fastjson正常序列化和反序列化
enumTypes.stream().forEach(aClass -> {
setEnumParser(aClass, parserConfig);
setEnumSerializer(aClass, serializeConfig);
});
//配置生效
FastJsonConfig config = converter.getFastJsonConfig();
config.setSerializeConfig(serializeConfig);
config.setParserConfig(parserConfig);
/*将fastjson设置为序号为0的json解析器,同时要在pom中的spring-boot-starter-web依赖添加exclusion
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</exclusion>
</exclusions>
</dependency>
*/
converters.add(0, converter);
}
/**
* @return 获取 com.school.information.enums 包下的所有枚举类
*/
private Set<Class<?>> getEnumTypes() {
//将扫描路径替换为自己枚举类所在的包名
Set<Class<?>> classes = ClassScanner.scanPackage("com.school.information.enums");
// log.info("加载枚举包下所以枚举类成功,获取结果 = {}", JSON.toJSONString(classes));
return classes;
}
/**
* 为枚举配置序列化方法
*
* @param aClass 枚举class
* @param serializeConfig 序列化配置
*/
private void setEnumSerializer(Class aClass, SerializeConfig serializeConfig) {
serializeConfig.put(aClass, (JSONSerializer serializer, Object object, Object fileName, Type type, int features) -> {
SerializeWriter out = serializer.out;
if (object instanceof BaseEnum) {
BaseEnum BaseEnum = (BaseEnum) object;
out.write(BaseEnum.getCode().toString());
} else {
out.writeEnum((Enum<?>) object);
}
});
}
/**
* 为枚举配置反序列化方法
*
* @param aClass 枚举class
* @param parserConfig 反序列化方法
*/
private void setEnumParser(Class aClass, ParserConfig parserConfig) {
parserConfig.putDeserializer(aClass, new ObjectDeserializer() {
@Override
public <T> T deserialze(DefaultJSONParser parser, Type type, Object o) {
final JSONLexer lexer = parser.lexer;
final int token = lexer.token();
Class cls = (Class) type;
Object[] enumConstants = cls.getEnumConstants();
if (BaseEnum.class.isAssignableFrom(cls)) {
for (Object enumConstant : enumConstants) {
BaseEnum BaseEnum = (BaseEnum) enumConstant;
Object enumCodeObject = BaseEnum.getCode();
int enumCode = Integer.parseInt(enumCodeObject.toString());
if (lexer.intValue() == enumCode) {
return (T) BaseEnum;
}
}
} else {
//没实现EnumValue接口的 默认的按名字或者按ordinal
if (token == JSONToken.LITERAL_INT) {
int intValue = lexer.intValue();
lexer.nextToken(JSONToken.COMMA);
if (intValue < 0 || intValue > enumConstants.length) {
throw new JSONException(String.format("parse enum %s error, value : %s", cls.getName(), intValue));
}
return (T) enumConstants[intValue];
} else if (token == JSONToken.LITERAL_STRING) {
return (T) Enum.valueOf(cls, lexer.stringVal());
}
}
return null;
}
@Override
public int getFastMatchToken() {
return JSONToken.LITERAL_INT;
}
});
}
private List<MediaType> getMediaType() {
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.APPLICATION_JSON);
mediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
return mediaTypes;
}
}