背景
前后端接口交互中,经常会出现一些枚举值,比如订单状态。前端请求参数一般是整数值,相应地,后端接收参数也用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:用于获取反序列字段的类型
@Slf4j
public 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
}
}
接收请求的类定义:
@Data
public class TestReq {
private String name;
@JsonDeserialize(using = CodeEnumDeserializer.class) // 给字段指定定义的反序列化器
private Direction direction;
}
也可以利用@JsonComponent
注解配置成全局的,只需要在CodeEnumDeserializer
类上加@JsonComponent
(参考:Spring Boot中使用@JsonComponent)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。