SpringBoot自定义枚举序列化方式

简介: SpringBoot自定义枚举序列化方式

在平常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": "正常"
    }
}
目录
相关文章
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
26天前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
124 0
|
27天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
139 2
|
14天前
|
JSON 前端开发 数据格式
前端的全栈之路Meteor篇(五):自定义对象序列化的EJSON介绍 - 跨设备的对象传输
EJSON是Meteor框架中扩展了标准JSON的库,支持更多数据类型如`Date`、`Binary`等。它提供了序列化和反序列化功能,使客户端和服务器之间的复杂数据传输更加便捷高效。EJSON还支持自定义对象的定义和传输,通过`EJSON.addType`注册自定义类型,确保数据在两端无缝传递。
|
2月前
|
Java Spring
springboot静态资源目录访问,及自定义静态资源路径,index页面的访问
本文介绍了Spring Boot中静态资源的访问位置、如何进行静态资源访问测试、自定义静态资源路径和静态资源请求映射,以及如何处理自定义静态资源映射对index页面访问的影响。提供了两种解决方案:取消自定义静态资源映射或编写Controller来截获index.html的请求并重定向。
springboot静态资源目录访问,及自定义静态资源路径,index页面的访问
|
30天前
|
消息中间件 存储 Java
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
大数据-58 Kafka 高级特性 消息发送02-自定义序列化器、自定义分区器 Java代码实现
41 3
|
30天前
|
消息中间件 存储 分布式计算
大数据-61 Kafka 高级特性 消息消费02-主题与分区 自定义反序列化 拦截器 位移提交 位移管理 重平衡
大数据-61 Kafka 高级特性 消息消费02-主题与分区 自定义反序列化 拦截器 位移提交 位移管理 重平衡
22 1
|
1月前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
48 2
|
2月前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
27天前
|
前端开发 Java 数据库
springBoot:template engine&自定义一个mvc&后端给前端传数据&增删改查 (三)
本文介绍了如何自定义一个 MVC 框架,包括后端向前端传递数据、前后端代理配置、实现增删改查功能以及分页查询。详细展示了代码示例,从配置文件到控制器、服务层和数据访问层的实现,帮助开发者快速理解和应用。