Swagger枚举类型

Swagger Enum

背景

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

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

问题

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

public class PersonDTO { @ApiModelProperty("主键") private Long id; @ApiModelProperty("性别: 1男,2女") private Integer gender; }

这样一旦再多加一种性别:
gender = 3;// 表示中性

你就需要找到所有地方,都改下,但凡漏掉一个地方,就可能导致前端的对应不上,这种隐藏的Bug是十分危险的。

解决方案

定义枚举,实现BaseEnum接口
public interface BaseEnum { /** * 获取枚举类的值 * * @return Object */ Object getValue(); /** * 获取枚举类的说明 * * @return String */ String getDesc();

比如文件类的枚举变量:

public enum FileServiceTypeEnum implements BaseEnum { /** * 本地文件服务 */ LOCAL(1, FileServiceNameConst.LOCAL, "本地文件服务"), /** * 阿里OSS文件服务 */ ALI_OSS(2, FileServiceNameConst.ALI_OSS, "阿里OSS文件服务"), /** * 七牛文件服务 */ QI_NIU_OSS(3, FileServiceNameConst.QI_NIU_OSS, "七牛文件服务"); private Integer locationType; private String serviceName; private String desc; FileServiceTypeEnum(Integer locationType, String serviceName, String desc) { this.locationType = locationType; this.serviceName = serviceName; this.desc = desc; } @Override public Integer getValue() { return this.locationType; } @Override public String getDesc() { return this.desc; } public String getServiceName() { return serviceName; } }
为JavaBean 添加@ApiModelPropertyEnum注解
public class FileDTO { @ApiModelPropertyEnum(FileServiceTypeEnum.class) private Integer fileLocationType; @ApiModelProperty("文件名称") private String fileName;
ApiModelPropertyEnum注解

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

public class SmartSwaggerApiModelEnumPlugin 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()) { Class<? extends BaseEnum> aClass = annotation.get().value(); String enumInfo = BaseEnum.getInfo(aClass); String enumDesc = annotation.get().enumDesc(); context.getBuilder().required(annotation.transform(toIsRequired()).or(false)) .description(enumDesc +":"+enumInfo) .example(annotation.transform(toExample()).orNull()); } } @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; }; } }
swagger显示效果

效果如下:
image.png

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

为了前端使用vue-enum

因为swagger文档多用于前端,后端人员较少,前端使用的枚举维护是:vue-enum

所以直接用Java代码生成了前端代码,这样前端人员直接copy走就可以了。

关爱前端,节省时间。

当然如果前端是app端的话,想修改返回结果,可以直接修改
BaseEnum.getInfo() 方法


作者简介:
卓大, 1024创新实验室主任,混迹于各个技术,熟悉点java,略懂点前端。