背景
以下是我们一般的枚举类配合SpringMvc使用方式。
枚举类如下:
public enum Distance {
KILOMETER("km", 1000),
MILE("miles", 1609.34),
METER("meters", 1);
private String unit;
private final double meters;
Distance(String unit, double meters) {
this.unit = unit;
this.meters = meters;
}
实体类如下:
public class City {
private String id;
private Distance distance;
Controller如下:
-- /api/v1?distance=KILOMETER
@GetMapping
public void get(Distance distance)
-- /api/v1?distance=KILOMETER&id=1
@GetMapping
public void get(City city)
-- json
{
"id": "1",
"distance": "KILOMETER"
}
@PostMapping
public void post(@RequestBody City city)
-- 反序列化
@GetMapping
public City get()
-- json
{
"id": "1",
"distance": "KILOMETER"
}
默认所有的参数和响应都是大写的字符串枚举名称
优化
我们想自定义序列化和反序列化字段,例如使用unit或者meters属性。
针对普通请求参数
-- /api/v1?distance=KILOMETER
@GetMapping
public void get(Distance distance)
-- /api/v1?distance=KILOMETER&id=1
@GetMapping
public void get(City city)
1. 定义IEnum接口
public interface IEnum<T extends Serializable> {
T getValue();
}
2.基于SpringMvc的Converter实现StringToEnum转换
public class StringToEnumConvertFactory implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return IEnum.class.isAssignableFrom(targetType.getObjectType()) && sourceType.getObjectType() == String.class;
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
IEnum[] enums = (IEnum[]) targetType.getObjectType().getEnumConstants();
for (IEnum anEnum : enums) {
if (Objects.equals(anEnum.getValue(), source)) {
return anEnum;
}
}
return null;
}
}
3.把转换器注册到SpringMvc
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToEnumConvertFactory());
}
4.自定义枚举实现定义IEnum接口
public enum Distance implements IEnum<String> {
KILOMETER("km", 1000),
MILE("miles", 1609.34),
METER("meters", 1);
private String unit;
private final double meters;
Distance(String unit, double meters) {
this.unit = unit;
this.meters = meters;
}
@Override // 这里选择转换的属性
public String getValue() {
return unit;
}
}
实现效果如下:
-- /api/v1?distance=km
-- /api/v1?distance=miles
@GetMapping
public void get(Distance distance)
-- /api/v1?distance=km&id=1
@GetMapping
public void get(City city)
针对RequestBody参数
-- json
{
"id": "1",
"distance": "KILOMETER"
}
@PostMapping
public void post(@RequestBody City city)
直接在枚举的指定get方法使用@JsonValue
注解即可。
public enum Distance implements IEnum<String> {
KILOMETER("km", 1000),
MILE("miles", 1609.34),
METER("meters", 1);
private String unit;
private final double meters;
Distance(String unit, double meters) {
this.unit = unit;
this.meters = meters;
}
@Override
@JsonValue // 这里配置
public String getValue() {
return unit;
}
}
实现效果如下:
-- json
{
"id": "1",
"distance": "km"
}
@PostMapping
public void post(@RequestBody City city)
针对枚举类型响应
直接在get方法使用@JsonValue
注解即可。跟上面方式一样
实现效果如下:
-- 反序列化
@GetMapping
public City get()
-- json
{
"id": "1",
"distance": "km"
}
更多Jackson序列化和反序列化参考:https://blog.csdn.net/hj_5346/article/details/127269700
- @JsonFormat(shape = JsonFormat.Shape.OBJECT)
- @JsonValue
- @JsonSerialize(using = DistanceSerializer.class)
- @JsonProperty(“distance-in-km”)
- @JsonCreator
- @JsonDeserialize(using = CustomEnumDeserializer.class)