Swagger枚举类型

9/7/2021

# 一、背景与问题

经常后端会返回给前端一个枚举定义,比如性别:gender

gender = 1;// 表示男性
gender = 2;// 表示女性
1
2

在给javabean添加swagger @ApiModelProperty注解的时候,就需要额外说明,每个值代表的是什么含义,如下:

public class PersonVO {
    @ApiModelProperty("性别: 1男,2女")
    private Integer gender;
}
1
2
3
4

这样一旦再多加一种性别:gender = 3;// 表示中性,你就需要找到所有地方,都改下,但凡漏掉一个地方,就可能导致前端的对应不上,这种隐藏的Bug是十分危险的。

# 二、解决方案

# 2.1、BaseEnum接口

public interface BaseEnum {

    /**
     * 获取枚举类的值
     */
    Object getValue();

    /**
     * 获取枚举类的说明
     */
    String getDesc();
1
2
3
4
5
6
7
8
9
10
11

比如商品状态类的枚举变量:

@AllArgsConstructor
@Getter
public enum GoodsStatusEnum implements BaseEnum {
    APPOINTMENT(1, "预约中"),
    SELL(2, "售卖中"),
    SELL_OUT(3, "售罄");

    private final Integer value;
    private final String desc;
}
1
2
3
4
5
6
7
8
9
10

# 2.2、枚举注解

我们定义了一个枚举注解:@ApiModelPropertyEnum,在javabean中枚举字段添加

@Data
public class GoodsVO  {

    @ApiModelProperty("商品名称")
    private String goodsName;

    @ApiModelPropertyEnum(GoodsStatusEnum.class)
    private Integer goodsStatus;
1
2
3
4
5
6
7
8

# 2.3、效果

swagger效果如下:

你会发现这不是前端代码吗?为什么要这样?

# 2.4、前端vue-enum配合

因为swagger文档多用于前端,后端人员较少,前端使用的枚举维护是:vue-enum (opens new window)
所以直接用Java代码生成了前端代码,这样前端人员直接copy走就可以了。
关爱前端,节省时间
当然如果前端是app端的话,想修改返回结果,可以直接修改BaseEnum.getInfo() 方法

# 三、实现原理

@ApiModelPropertyEnum 注解

我们自己实现了一个swagger插件ModelPropertyBuilderPlugin插件:SwaggerApiModelPropertyEnumPlugin,在插件中使用@ApiModelPropertyEnum注解,这样在swagger文档中就可以很好的显示了

@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1)
public class SwaggerApiModelPropertyEnumPlugin implements ModelPropertyBuilderPlugin {

    @Override
    public void apply(ModelPropertyContext context) {
        Optional<ApiModelPropertyEnum> annotation = Optional.absent();

        if (context.getAnnotatedElement().isPresent()) {
            annotation = annotation.or(findApiModePropertyAnnotation(context.getAnnotatedElement().get()));
        }
        if (context.getBeanPropertyDefinition().isPresent()) {
            annotation = annotation.or(findPropertyAnnotation(context.getBeanPropertyDefinition().get(), ApiModelPropertyEnum.class));
        }

        if (annotation.isPresent()) {
            ApiModelPropertyEnum anEnum = annotation.get();
            String enumInfo = BaseEnum.getInfo(anEnum.value());
            context.getBuilder()
                    .required(annotation.transform(toIsRequired()).or(false))
                    .description(anEnum.desc() + ":" + enumInfo)
                    .example(annotation.transform(toExample()).orNull())
                    .isHidden(anEnum.hidden());
        }
    }

    @Override
    public boolean supports(DocumentationType delimiter) {
        return SwaggerPluginSupport.pluginDoesApply(delimiter);
    }

    static Function<ApiModelPropertyEnum, Boolean> toIsRequired() {
        return annotation -> annotation.required();
    }

    public static Optional<ApiModelPropertyEnum> findApiModePropertyAnnotation(AnnotatedElement annotated) {
        return Optional.fromNullable(AnnotationUtils.getAnnotation(annotated, ApiModelPropertyEnum.class));
    }

    static Function<ApiModelPropertyEnum, String> toExample() {
        return annotation -> {
            String example = annotation.example();
            if (StringUtils.isBlank(example)) {
                return "";
            }
            return example;
        };
    }
}
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

# 联系我们

1024创新实验室-主任:卓大 (opens new window),混迹于各个技术圈,研究过计算机,熟悉点 java,略懂点前端。
1024创新实验室(河南·洛阳) (opens new window) 致力于成为中原领先、国内一流的技术团队,以技术创新为驱动,合作各类项目(软件外包、技术顾问、培训等等)。

加 主任 “卓大” 微信
拉你入群,一起学习
关注 “小镇程序员”
分享代码与生活、技术与赚钱
请 “1024创新实验室” 喝咖啡
支持我们的开源与分享

告白气球 (钢琴版)
JESSE T