swagger3 展示枚举类型

1 篇文章 0 订阅
1 篇文章 0 订阅

原文是基于swagger2编写的,在原文的基础上做了相应的改造。适用于swagger3

原文:swagger展示枚举类型
https://blog.csdn.net/weixin_50276625/article/details/115858744

改造点:

1、将 @SwaggerDisplayEnum 注解改为 SwaggerDisplayEnum 接口,使用default方法实现 description() 描述。
2、针对swagger3,实现类做了相应的调整

一、pom.xml的jar依赖

<!-- swagger3 生成接口api文档 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
    <scope>provided</scope>
</dependency>

二、SwaggerDisplayEnum 接口

public interface SwaggerDisplayEnum {
    Object getValue();

    String getInfo();

    /**
     * 获取字典描述value - info
     */
    default String description() {
        return getValue().toString() + "-" + getInfo();
    }
}

三、枚举类实例

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 文件来源类型,1-文件存储服务读取;2-参数Base64传递;
 */
@Getter
@AllArgsConstructor
public enum DictFileFromType implements SwaggerDisplayEnum {

    /**文件存储服务读取*/
    FILE_STORAGE(1, "文件存储服务读取[默认]"),

    /**参数Base64传递*/
    PARAM_BASE64(2, "参数Base64传递");

    private Integer value;
    private String info;
}

四、需要显示枚举类型的字段属性

通过 @ApiModelProperty 的 notes 属性标识枚举类的全路径
/**
 * 文件的来源类型
 * @see  DictFileFromType
 */
@ApiModelProperty(value = "word文件来源类型(可选参数).", notes = "***.dict.DictFileFromType")
private Integer docFileFromType = DictFileFromType.FILE_STORAGE.getValue();

五、swaggerConfig 配置文件

@ConditionalOnProperty(name = “spring.profiles.active”, havingValue = “dev”, matchIfMissing = true),仅当开发环境的时候才加载,生产环境则不会加载swagger

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.PropertySpecificationBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.schema.Annotations;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;
import springfox.documentation.spring.web.plugins.Docket;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Configuration
@EnableOpenApi
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev", matchIfMissing = true)
public class Swagger3Config implements ModelPropertyBuilderPlugin {

    /**
     * 创建swagger API文档,访问地址http://host:port/productName/swagger-ui/
     * <p>1、apiInfo():增加API相关的信息.
     * <p>2、select():返回ApiSelectorBuilder实例,用于控制哪些接口暴露给swagger来展现.
     * <p>3、apis():指定扫描的路径来指定要建立的API目录.
     *     RequestHandlerSelectors 用于配置要扫描的包,以下参数可选:
     *         basePackage():指定要扫描的包.
     *         any():扫描全部.
     *         none():都不扫描.
     *         withMethodAnnotation:扫描方法上的注解, 参数是一个注解的反射对象.
     *         withClassAnnotation:扫描类上的注解, 参数是一个注解的反射对象.
     *             例如:withClassAnnotation(RestController .class) 只扫描类上有@RestController的生成文档.
     * <p>4、paths():过滤什么路径.
     */
    @Bean
    public Docket createApi() {
        log.info("====> [Swagger3]开启.");
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * Swagger2主界面信息,描述api的基本信息用于展示
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("api文档")
                .description("《api》接口定义和规范")
                .termsOfServiceUrl("http://www.xxxx.com/")
                .contact(new Contact("风舞苍月", "http://www.xxxx.com/", "fengwu@xxxx.com"))
                .version("1.0")
                .license("版权所有©xxxx科技有限公司")
                .build();
    }

    @Override
    public void apply(ModelPropertyContext context) {
        //为枚举字段设置注释
        descForEnumFields(context);
    }

    /**
     * 返回是否应根据给定的分隔符调用插件
     */
    @Override
    public boolean supports(DocumentationType documentationType) {
        return true;
    }

    /**
     * 为枚举字段设置注释
     */
    private void descForEnumFields(ModelPropertyContext context) {
        Optional<ApiModelProperty> annotation = Optional.empty();

        // 找到 @ApiModelProperty 注解修饰的枚举类
        if (context.getBeanPropertyDefinition().isPresent()) {
            annotation = Annotations.findPropertyAnnotation(context.getBeanPropertyDefinition().get(), ApiModelProperty.class);
        }

        //没有@ApiModelProperty 或者 notes 属性没有值,直接返回
        if (!annotation.isPresent() || StringUtils.isEmpty((annotation.get()).notes())) {
            return;
        }

        //@ApiModelProperties中的notes指定的class类型
        Class rawPrimaryType;
        try {
            rawPrimaryType = Class.forName((annotation.get()).notes());
        } catch (ClassNotFoundException e) {
            //如果指定的类型无法转化,直接忽略
            return;
        }

        Object[] subItemRecords = null;
        // 判断 rawPrimaryType 是否为枚举,且实现了 SwaggerDisplayEnum 接口
        if (Enum.class.isAssignableFrom(rawPrimaryType) && SwaggerDisplayEnum.class.isAssignableFrom(rawPrimaryType)) {
            // 拿到枚举的所有的值
            subItemRecords = rawPrimaryType.getEnumConstants();
        } else {
            return;
        }

        final List<String> displayValues = Arrays.stream(subItemRecords).filter(Objects::nonNull)
                        // 调用枚举类的 description 方法
                        .map(p -> ((SwaggerDisplayEnum) p).description()).filter(Objects::nonNull).collect(Collectors.toList());

        String joinText = " (" + String.join("; ", displayValues) + ")";
        try {
            // 拿到字段上原先的描述
            Field mField = PropertySpecificationBuilder.class.getDeclaredField("description");
            mField.setAccessible(true);
            // context 中的 builder 对象保存了字段的信息
            joinText = mField.get(context.getSpecificationBuilder()) + joinText;
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        // 设置新的字段说明并且设置字段类型
        context.getSpecificationBuilder().description(joinText);
    }

}

六、SpringMVC拦截器配置

如果是实现WebMvcConfigurer接口则无需配置。

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * 配置SpringMvc不拦截 swagger3 的接口
     * @param registry
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
    }
}

七、SpringBoot启动类添加文档连接

public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication.run(DocConvertApplication.class, args);

    if(context.containsBean("swagger3Config")){
        try {
            // 访问地址http://host:port/productName/swagger-ui/
            log.info("====> [Swagger3]文档的访问路径:http://{}:{}/{}/swagger-ui/index.html",
                    InetAddress.getLocalHost().getHostAddress(),
                    context.getEnvironment().getProperty("server.port"),
                    context.getEnvironment().getProperty("spring.application.name"));
        } catch (Exception ignored){}
    }
}

八、展示效果

实体类

@ApiModel("获取认证结果的参数")
@Getter
@Setter
public class AuthFaceResultVO {

    /**
     * 认证状态,{@link DictAuthFaceState}
     */
    @ApiModelProperty(value = "认证状态", notes = "xxx.dict.web.DictAuthFaceState")
    private Integer authState;

}

字典类

@Getter
@AllArgsConstructor
public enum DictAuthFaceState implements SwaggerDisplayEnum {
    /**认证成功*/
    AUTHENTICATED(0, "认证成功"),

    /**未认证*/
    UNAUTHENTICATED(1, "未认证"),

    /**认证中*/
    AUTHENTICATING(2, "认证中"),

    /**已失效*/
    INVALID(3, "已失效");

    private Integer value;
    private String info;
}

swagger显示效果
在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风舞苍月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值