SpringBoot实现自定义枚举字段值关联映射

83次阅读
没有评论

SpringBoot 中,默认枚举的响应和请求都是以枚举名称为对应值,如果我们需要自定枚举的响应值和请求值,就需要单独处理,本次我们就来聊聊一些比较简单快捷方便的处理方式。

响应值

总所周知,SpringBoot内置的 HTTP 响应结构序列化是使用的 Jackson,所以我们只需要在对应的枚举字段上加上@JsonValue 即可,例如:

@AllArgsConstructor  
@Getter  
public enum ApprovalStatus {WAIT(1, " 未审核 "),  
    SUCCESS(2, " 审核成功 "),  
    FAIL(3, " 审核失败 ");  

    @JsonValue  
    private final Integer index;  
    private final String desc;  

}

这样,在响应结构体中就会直接返回枚举中的 index 字段的值。

请求值

按照响应值的思路,之前看网上说只要加 @JsonValue,SpringBoot 在收到请求体的时候也会自动映射枚举值中的字段来进行匹配注入,但是实际传输的index 会以枚举定义的序列来递增查找匹配注入,这就和我们实际需求结果的不符。

例如不加处理,我们请求 status 的值为1,我们得到的枚举为:

SUCCESS(2, " 审核成功 ")

由此可以看出,这显然不符合我们的业务逻辑,所以我们需要自定义 JSON 反序列化来实现匹配注入,首先我们需要定义一个公共的枚举接口(此处继承了 MybatisPlusIEnum接口实现数据库枚举注入):

/**  
 * 公共基础枚举  
 * @author Licoy  
 * */
public interface BaseEnum<T extends Serializable> extends IEnum<T> {}

接着我们需要实现 JsonDeserializer 接口,这里我们使用动态的获取上下文需要注入的枚举类型,所以我们还需要实现 ContextualDeserializer 接口:

/**  
 * 请求枚举 JSON 反序列化  
 * @author Licoy  
 * */
@NoArgsConstructor  
@AllArgsConstructor  
public class RequestEnumJsonDeserialize extends JsonDeserializer<BaseEnum<?>> implements ContextualDeserializer {  

    private JavaType type;  

    @Override  
    public BaseEnum<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {if (this.type == null || !this.type.isEnumType()) {return null;}  
        ObjectCodec oc = p.getCodec();  
        JsonNode node = oc.readTree(p);  

        if (node == null) {return null;}  
        if (!(node instanceof IntNode)) {return null;}  
        Object[] enumConstants = this.type.getRawClass().getEnumConstants();  
        for (Object e : enumConstants) {if (e instanceof BaseEnum) {BaseEnum<?> ie = (BaseEnum<?>) e;  
                if (ie.getValue().equals(node.asInt())) {return ie;}  
            }  
        }  
        return null;  
    }  

    @Override  
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {JavaType type = ctxt.getContextualType() != null  
 ? ctxt.getContextualType()  
                : property.getMember().getType();  
        return new RequestEnumJsonDeserialize(type);  
    }  
}

到这里,我们就可以在实现 BaseEnum 接口的枚举上注入自定义字段值的枚举,不过在此之前我们需要在对应的枚举上加上使用反序列注解:

@JsonDeserialize(using = RequestEnumJsonDeserialize.class)

如果项目中枚举定义有很多,每个枚举类都去添加 @JsonDeserialize 未免有些麻烦,所以我们直接将此写到 BaseEnum 上,只要实现此接口的都可以实现自定义字段的枚举注入:

/**  
 * 公共基础枚举  
 * @author Licoy  
 * */
@JsonDeserialize(using = RequestEnumJsonDeserialize.class)  
public interface BaseEnum<T extends Serializable> extends IEnum<T> {}

参考

憧憬Licoy
版权声明:本站原创文章,由 憧憬Licoy2022-06-12发表,共计2203字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码
载入中...