puzhibing
2023-10-08 22199bbdda579861736420fe26c2873ab0f5d21c
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package com.sinata.rest.config;
 
import com.fasterxml.classmate.ResolvedType;
import com.google.common.base.Optional;
import com.sinata.common.enums.annotation.SwaggerCodeDisplayEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.ModelPropertyBuilder;
import springfox.documentation.schema.Annotations;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.swagger.schema.ApiModelProperties;
 
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
 
/**
 * <p>
 * swagger 处理枚举描述
 * </p>
 *
 * @ClassName com.sinata.data.common.config.SwaggerDisplayConfig
 * @Description swagger 处理枚举描述
 * @Author BaiHua
 * @Date 2019/10/19 0:34
 */
@Component
@Primary
@Slf4j
public class SwaggerCodeDisplayConfig implements ModelPropertyBuilderPlugin {
 
    /**
     * 是否允许swagger
     */
    @Value("${swagger.enable:true}")
    private Boolean enableSwagger;
 
    @Override
    public void apply(ModelPropertyContext context) {
        //如果不支持swagger的话,直接返回
        if (!enableSwagger) {
            return;
        }
 
        //获取当前字段的类型
        final Class fieldType = context.getBeanPropertyDefinition().get().getField().getRawType();
 
        //设置对数字的字段设置默认的example
        setDefaultExample(context, fieldType);
 
        //为枚举字段设置注释
        descForEnumFields(context, fieldType);
    }
 
    /**
     * 为枚举字段设置注释
     */
    private void descForEnumFields(ModelPropertyContext context, Class fieldType) {
        Optional<ApiModelProperty> annotation = Optional.absent();
 
        if (context.getAnnotatedElement().isPresent()) {
            annotation = annotation
                    .or(ApiModelProperties.findApiModePropertyAnnotation(context.getAnnotatedElement().get()));
        }
        if (context.getBeanPropertyDefinition().isPresent()) {
            annotation = annotation.or(Annotations.findPropertyAnnotation(
                    context.getBeanPropertyDefinition().get(),
                    ApiModelProperty.class));
        }
 
        //没有@ApiModelProperty 或者 notes 属性没有值,直接返回
        if (!annotation.isPresent() || StringUtils.isBlank((annotation.get()).notes())) {
            return;
        }
 
        //@ApiModelProperties中的notes指定的class类型
        Class rawPrimaryType;
        try {
            rawPrimaryType = Class.forName((annotation.get()).notes());
        } catch (ClassNotFoundException e) {
            //如果指定的类型无法转化,直接忽略
            return;
        }
 
        //如果对应的class是一个@SwaggerCodeDisplayEnum修饰的枚举类,获取其中的枚举值
        Object[] subItemRecords = null;
        SwaggerCodeDisplayEnum swaggerDisplayEnum = AnnotationUtils
                .findAnnotation(rawPrimaryType, SwaggerCodeDisplayEnum.class);
        if (null != swaggerDisplayEnum && Enum.class.isAssignableFrom(rawPrimaryType)) {
            subItemRecords = rawPrimaryType.getEnumConstants();
        }
        if (null == subItemRecords) {
            return;
        }
 
        //从annotation中获取对应的值和描述的变量名
        String indexName = swaggerDisplayEnum.indexName();
        String markName = swaggerDisplayEnum.markName();
        if (StringUtils.isBlank(indexName) || StringUtils.isBlank(markName)) {
            return;
        }
 
        final List<String> displayValues = Arrays.stream(subItemRecords).filter(Objects::nonNull).map(item -> {
            Class currentClass = item.getClass();
 
            String value;
            String desc;
            try {
                Field valueField = currentClass.getField(indexName);
                Field descField = currentClass.getField(markName);
                valueField.setAccessible(true);
                descField.setAccessible(true);
                // index 类型 注解
                value = valueField.get(item).toString();
                desc = descField.get(item).toString();
            } catch (NoSuchFieldException | IllegalAccessException e) {
                log.warn("获取枚举的属性和值失败, {}", e.getMessage());
                return null;
            }
            return value + " : " + desc;
        }).filter(Objects::nonNull).collect(Collectors.toList());
 
        String joinText = " (" + String.join("; ", displayValues) + ")";
        try {
            Field mField = ModelPropertyBuilder.class.getDeclaredField("description");
            mField.setAccessible(true);
            joinText = mField.get(context.getBuilder()) + joinText;
        } catch (Exception e) {
            log.error(e.getMessage());
        }
 
        final ResolvedType resolvedType = context.getResolver().resolve(fieldType);
        context.getBuilder().description(joinText).type(resolvedType);
    }
 
    /**
     * 设置默认的example
     */
    private void setDefaultExample(ModelPropertyContext context, Class fieldType) {
        if (Number.class.isAssignableFrom(fieldType)) {
            context.getBuilder().example("1");
        }
        if (Boolean.class.isAssignableFrom(fieldType)) {
            context.getBuilder().example("true");
        }
    }
 
    @Override
    public boolean supports(DocumentationType documentationType) {
        return true;
    }
}