共计 2203 个字符,预计需要花费 6 分钟才能阅读完成。
在 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 反序列化来实现匹配注入,首先我们需要定义一个公共的枚举接口(此处继承了 MybatisPlus
的IEnum
接口实现数据库枚举注入):
/**
* 公共基础枚举
* @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> {}