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

7次阅读
没有评论

共计 2225 个字符,预计需要花费 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> {}

参考

正文完
 0
litao2024
版权声明:本站原创文章,由 litao2024 于2024-06-06发表,共计2225字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码