背景
前后端接口交互中,常常会呈现一些枚举值,比方订单状态。前端申请参数个别是整数值,相应地,后端接管参数也用int类型,而后再转换成对应的枚举类型。
每次都须要手动转换未免有点麻烦,有没有什么方法能够让接管到的int值主动转换成我想要的枚举值呢?
实现
定义一个接口,示意能够用int获取code的枚举类型:
public interface CodeEnum { int getCode();}
定义枚举类,实现这个接口:
public enum Direction implements CodeEnum { NORTH(0), EAST(1), SOUTH(2), WEST(3); Direction(int code) { this.code = code; } private final int code; @Override public int getCode() { return code; }}
定义一个反序列化类,继承JsonDeserializer、实现ContextualDeserializer接口
JsonDeserializer:用于自定义反序列化器,将JSON的字段值反序列化成咱们想要的类型,在这里咱们须要把int示意的枚举值反序列化成具体枚举类的枚举值
ContextualDeserializer:用于获取反序列字段的类型
@Slf4jpublic class CodeEnumDeserializer extends JsonDeserializer<CodeEnum> implements ContextualDeserializer { private Class<? extends CodeEnum> propertyClass; // 记录枚举字段的类,用于获取其定义的所有枚举值 public CodeEnumDeserializer() { log.info("Construct with no args"); // 必须有无参结构器,spring会调用 } public CodeEnumDeserializer(Class<? extends CodeEnum> propertyClass) { this.propertyClass = propertyClass; } @Override public CodeEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException { int code; try { code = p.getIntValue(); } catch (JsonParseException e) { return null; } log.info("Enum code: {}", code); return Arrays.stream(propertyClass.getEnumConstants()) // 调用Class的这个办法,获取枚举类的所有枚举值 .filter(e -> e.getCode() == code) .findAny() .orElseThrow(() -> new IllegalArgumentException("No such code of " + propertyClass.getSimpleName())); } @SuppressWarnings({"unchecked"}) @Override public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException { log.info("Construct with property class"); return new CodeEnumDeserializer((Class<? extends CodeEnum>) property.getType().getRawClass()); // 获取枚举字段的类型Class }}
接管申请的类定义:
@Datapublic class TestReq { private String name; @JsonDeserialize(using = CodeEnumDeserializer.class) // 给字段指定定义的反序列化器 private Direction direction;}
也能够利用@JsonComponent
注解配置成全局的,只须要在CodeEnumDeserializer
类上加@JsonComponent
(参考:Spring Boot中应用@JsonComponent)