在平常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<Integer, ? 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": "正常" } }