SpringBoot自定义枚举序列化方式
2022-06-22 23:34:12 669
在平常web开发中, 或多或少的会使用到枚举类型
但是springboot对枚举的序列化并不太符合实际开发需求
比如
public enum MerchantStatusEnum {
NORMAL(100, "正常"),
BAN(200, "封禁");
private final Integer type;
private final String name;
MerchantStatusEnum(Integer type, String name) {
this.name = name;
this.type = type;
}
}
序列化后是这样的
{
"status": "NORMAL"
}
而且使用枚举接受请求参数时, 字段也必须采用如上格式, 对前端不太便利.
所以自定义枚举的序列化器进行自定义的序列化
改造如下
定义接口
public interface TypeEnum {
/**
* 由枚举实现
*
* @return 枚举类的type字段
*/
Integer getType();
/**
* 由枚举实现
*
* @return 枚举类的name字段
*/
String getName();
}
实现接口, 标记此枚举使用自定义的序列化方式
@Getter
public enum MerchantStatusEnum implements TypeEnum {
/**
* 正常
*/
NORMAL(100, "正常"),
/**
* 封禁
*/
BAN(200, "封禁");
@EnumValue
private final Integer type;
private final String name;
MerchantStatusEnum(Integer type, String name) {
this.name = name;
this.type = type;
}
}
type到枚举的映射方法
public class EnumUtil {
private static final Map<Class<? extends Enum<?>>, Map<?, ? extends Enum<? extends TypeEnum>>> CLASS_ENUM_MAP =
new ConcurrentHashMap<>(16);
@SuppressWarnings("unchecked")
public static <E extends Enum<E> & TypeEnum> E match(Class<E> enumClass, Integer type) {
var enumMap = CLASS_ENUM_MAP.get(enumClass);
if (Objects.isNull(enumMap)) {
var unmodifiableMap = Arrays.stream(enumClass.getEnumConstants())
.collect(Collectors.toUnmodifiableMap(TypeEnum::getType, v -> v));
CLASS_ENUM_MAP.putIfAbsent(enumClass, unmodifiableMap);
return unmodifiableMap.get(type);
}
return (E) enumMap.get(type);
}
}
自定义反序列化类
public class TypeEnumDeserializer extends StdDeserializer<TypeEnum> implements ContextualDeserializer {
public TypeEnumDeserializer() {
super((JavaType) null);
}
public TypeEnumDeserializer(JavaType valueType) {
super(valueType);
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
return new TypeEnumDeserializer(property.getType());
}
@Override
@SuppressWarnings("all")
public TypeEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return (TypeEnum) EnumUtil.match((Class) _valueClass, p.getIntValue());
}
}
注册到springboot中
@Configuration
@Slf4j
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
var stringHttpMessageConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
var converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(objectMapperForWebConvert());
converters.add(0, stringHttpMessageConverter);
converters.add(0, converter);
}
public ObjectMapper objectMapperForWebConvert() {
var om = new ObjectMapper();
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
var sm = new SimpleModule();
//自定义查找规则
sm.setDeserializers(new SimpleDeserializers() {
@Override
public JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config,
BeanDescription beanDesc) throws JsonMappingException {
var enumDeserializer = super.findEnumDeserializer(type, config, beanDesc);
if (enumDeserializer != null) {
return enumDeserializer;
}
//遍历枚举实现的接口, 查找反序列化器
for (var typeInterface : type.getInterfaces()) {
enumDeserializer = this._classMappings.get(new ClassKey(typeInterface));
if (enumDeserializer != null) {
return enumDeserializer;
}
}
return null;
}
});
sm.addDeserializer(TypeEnum.class, new TypeEnumDeserializer());
sm.addSerializer(TypeEnum.class, new JsonSerializer<>() {
@Override
public void serialize(TypeEnum value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeNumberField("type", value.getType());
gen.writeStringField("name", value.getName());
gen.writeEndObject();
}
@Override
public void serializeWithType(TypeEnum value, JsonGenerator gen, SerializerProvider serializers,
TypeSerializer typeSer) throws IOException {
var typeIdDef = typeSer.writeTypePrefix(gen, typeSer.typeId(value, JsonToken.VALUE_STRING));
serialize(value, gen, serializers);
typeSer.writeTypeSuffix(gen, typeIdDef);
}
});
om.registerModule(sm);
return om;
}
}
自此, 前端可以传递type值即可映射到枚举
{
"status": 100
}
后端的响应
{
"status": {
"type": 100,
"name": "正常"
}
}