# 背景
经常后端会返回给前端一个枚举定义,比如性别:gender
gender = 1;// 表示男性
gender = 2;// 表示女性
2
# 问题
在给javabean添加swagger @ApiModelProperty
注解的时候,就需要额外说明,每个值代表的是什么含义,如下:
public class PersonDTO {
@ApiModelProperty("主键")
private Long id;
@ApiModelProperty("性别: 1男,2女")
private Integer gender;
}
2
3
4
5
6
7
8
这样一旦再多加一种性别:
gender = 3;// 表示中性
你就需要找到所有地方,都改下,但凡漏掉一个地方,就可能导致前端的对应不上,这种隐藏的Bug是十分危险的。
# 解决方案
# 定义枚举,实现BaseEnum
接口
public interface BaseEnum {
/**
* 获取枚举类的值
*
* @return Object
*/
Object getValue();
/**
* 获取枚举类的说明
*
* @return String
*/
String getDesc();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
比如文件类的枚举变量:
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;
}
}
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
# 为JavaBean 添加@ApiModelPropertyEnum
注解
public class FileDTO {
@ApiModelPropertyEnum(FileServiceTypeEnum.class)
private Integer fileLocationType;
@ApiModelProperty("文件名称")
private String fileName;
2
3
4
5
6
7
# 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;
};
}
}
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
# swagger显示效果
效果如下:
你会发现这不是前端代码吗?为什么要这样?
# 为了前端使用vue-enum
因为swagger文档多用于前端,后端人员较少,前端使用的枚举维护是:vue-enum (opens new window)
所以直接用Java代码生成了前端代码,这样前端人员直接copy走就可以了。
关爱前端,节省时间。
当然如果前端是app端的话,想修改返回结果,可以直接修改
BaseEnum.getInfo()
方法
作者简介: 卓大 (opens new window), 1024创新实验室主任,混迹于各个技术圈,熟悉点java,略懂点前端。
![]() | ![]() | ![]() |
加“卓大”微信,入群 | 关注 1024创新实验室! | 我要请 1024创新实验室 喝胡辣汤~ |