Swagger扩展-枚举相关

源码:https://github.com/chenkaixin12121/study/tree/master/swagger_enum

枚举显示自定义描述

结果

Snipaste_2023-03-02_19-28-50

Snipaste_2023-03-02_19-27-48

代码
1
2
3
4
5
6
7
8
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SwaggerDisplayEnum {

String code() default "code";

String desc() default "desc";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
@Configuration
@Slf4j
public class SwaggerEnumPlugin implements ModelPropertyBuilderPlugin, ParameterBuilderPlugin {

/**
* json格式枚举显示
*
* @param context - context that can be used to override the model property attributes
*/
@Override
public void apply(ModelPropertyContext context) {
Optional<BeanPropertyDefinition> optional = context.getBeanPropertyDefinition();
if (!optional.isPresent()) {
return;
}

Class<?> fieldType = optional.get().getField().getRawType();
List<EnumKeyValue> enumKeyValueList = this.getDisplayValueList(fieldType);
if (CollectionUtils.isEmpty(enumKeyValueList)) {
return;
}
List<String> displayValueList = enumKeyValueList.stream().map(e -> e.getCode() + ":" + e.getDesc()).collect(Collectors.toList());
List<String> availableValueList = enumKeyValueList.stream().map(EnumKeyValue::getCode).collect(Collectors.toList());

PropertySpecificationBuilder specificationBuilder = context.getSpecificationBuilder();
Field descField = ReflectionUtils.findField(specificationBuilder.getClass(), "description");
ReflectionUtils.makeAccessible(descField);
String joinText = (ReflectionUtils.getField(descField, specificationBuilder) == null ? "" :
(ReflectionUtils.getField(descField, specificationBuilder) + ":")) + String.join(",", displayValueList);
specificationBuilder.description(joinText);

AllowableListValues allowableListValues = new AllowableListValues(availableValueList, "Integer");
specificationBuilder.enumerationFacet(builder -> builder.allowedValues(allowableListValues));
}

@Override
public boolean supports(DocumentationType documentationType) {
return true;
}

/**
* 表单提交枚举显示
*
* @param parameterContext - context that can be used to override the parameter attributes
*/
@Override
public void apply(ParameterContext parameterContext) {
Class<?> type = parameterContext.resolvedMethodParameter().getParameterType().getErasedType();
List<EnumKeyValue> enumKeyValueList = this.getDisplayValueList(type);
if (CollectionUtils.isEmpty(enumKeyValueList)) {
return;
}
List<String> displayValueList = enumKeyValueList.stream().map(e -> e.getCode() + ":" + e.getDesc()).collect(Collectors.toList());
List<String> availableValueList = enumKeyValueList.stream().map(EnumKeyValue::getCode).collect(Collectors.toList());

RequestParameterBuilder requestParameterBuilder = parameterContext.requestParameterBuilder();
Field descField = ReflectionUtils.findField(requestParameterBuilder.getClass(), "description");
ReflectionUtils.makeAccessible(descField);
String joinText = (ReflectionUtils.getField(descField, requestParameterBuilder) == null ? "" :
(ReflectionUtils.getField(descField, requestParameterBuilder) + ":")) + String.join(",", displayValueList);
requestParameterBuilder.description(joinText);

requestParameterBuilder.query(simpleParameterSpecificationBuilder -> simpleParameterSpecificationBuilder.model(modelSpecificationBuilder -> modelSpecificationBuilder.scalarModel(ScalarType.INTEGER)).enumerationFacet(enumerationElementFacetBuilder -> enumerationElementFacetBuilder.allowedValues(new AllowableListValues(availableValueList, "Integer"))));
}

private List<EnumKeyValue> getDisplayValueList(Class<?> type) {
if (!Enum.class.isAssignableFrom(type)) {
return Collections.emptyList();
}
SwaggerDisplayEnum annotation = AnnotationUtils.findAnnotation(type, SwaggerDisplayEnum.class);
if (annotation == null) {
return Collections.emptyList();
}

Object[] enumConstants = type.getEnumConstants();
String code = annotation.code();
String desc = annotation.desc();

return Arrays.stream(enumConstants).filter(Objects::nonNull).map(item -> {
Class<?> currentClass = item.getClass();
Field codeField = ReflectionUtils.findField(currentClass, code);
ReflectionUtils.makeAccessible(codeField);
Object codeStr = ReflectionUtils.getField(codeField, item);

Field descField = ReflectionUtils.findField(currentClass, desc);
ReflectionUtils.makeAccessible(descField);
Object descStr = ReflectionUtils.getField(descField, item);

return new EnumKeyValue(codeStr.toString(), descStr.toString());
}).collect(Collectors.toList());
}
}

@AllArgsConstructor
@Data
class EnumKeyValue {

private String code;

private String desc;
}

枚举反序列化接收自定义值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
public class JsonEnumDeserializer extends JsonDeserializer<IBaseEnum> implements ContextualDeserializer {

private Class<? extends IBaseEnum> propertyClass;

@Override
public IBaseEnum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String paramCode;
try {
paramCode = p.getValueAsString();
} catch (JsonParseException e) {
return null;
}
return Arrays.stream(propertyClass.getEnumConstants())
.filter(e -> {
String code = e.getCode().toString();
if (StringUtils.isNumeric(paramCode)) {
return Integer.valueOf(code).equals(Integer.valueOf(paramCode));
}
return StringUtils.equals(code, paramCode);
})
.findAny()
.orElseThrow(() -> new ResultException(BUSINESS_ERROR.getCode(), "枚举字段不匹配: " + propertyClass.getSimpleName()));
}

@SuppressWarnings({"unchecked"})
@Override
public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext, BeanProperty property) {
return new Code2EnumDeserializer((Class<? extends IBaseEnum>) property.getType().getRawClass());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ParamEnumConverter implements ConverterFactory<String, IBaseEnum> {

@Override
public <T extends IBaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToBaseEnum<>(targetType);
}

private static class StringToBaseEnum<T extends IBaseEnum> implements Converter<String, T> {

private final Class<T> enumType;

StringToBaseEnum(Class<T> enumType) {
this.enumType = enumType;
}

@Override
public T convert(String source) {
if (StringUtils.isNotBlank(source)) {
T[] enums = this.enumType.getEnumConstants();
for (T e : enums) {
if (e.getCode().toString().equals(source)) {
return e;
}
}
}
return null;
}
}
}
1
2
3
4
5
6
7
8
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverterFactory(new ParamEnumConverter());
}
}
1
2
3
4
5
6
7
8
9
10
11
@ApiModel(value = "订单信息")
@Data
public class OrderInfo {

@ApiModelProperty(value = "订单号", required = true)
private String orderNo;

@JsonDeserialize(using = JsonEnumDeserializer.class)
@ApiModelProperty(value = "订单状态", required = true)
private OrderStatusEnum status;
}