美文网首页
Springboot多模块项目,在公共模块整合Swagger2

Springboot多模块项目,在公共模块整合Swagger2

作者: 轻轻敲醒沉睡的心灵 | 来源:发表于2020-12-12 18:52 被阅读0次

    上一篇提到了SpringBoot整合Swagger2,但现在微服务盛行,一个项目可能就要搭建许多微服务,于是就想着将swagger2放到公共模块中,到时候直接把包引入就能用。基本上和上一篇一样,只不过就是把 swagger2的开关 和 描述提取到了配置文件中,使得引入公共模块的项目能在application.yml中控制swagger。

    1. 需要了解的一些知识

    1. Springboot整合Swagger2 - 简书 (jianshu.com)
    2. SpringBoot条件装配
    3. SpringBoot配置文件中的数据格式
    4. SpringBoot读取和使用配置文件中的数据

    2. 1. 导包

    <!--引入swagger -->
    <!-- 排除springfox-swagger2 引入的swagger-annotations、swagger-models 1.5.20版本,手动引入1.5.21版本的jar。
    因为在使用@ApiModelProperty注解在字段上时,如果字段的类型为Long或是int类型, 那么程序启动后,访问swagger-ui.html的页面,
    程序会报错: java.lang.NumberFormatException: For input string: "" -->
          <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.9.2</version>
                <exclusions>
                    <exclusion>
                        <groupId>io.swagger</groupId>
                        <artifactId>swagger-annotations</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>io.swagger</groupId>
                        <artifactId>swagger-models</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>2.9.2</version>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-annotations</artifactId>
                <version>1.5.21</version>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-models</artifactId>
                <version>1.5.21</version>
            </dependency>
    

    3. 配置

      1. 添加swagger属性文件,以后在项目的application.yml文件中配置
      
      @ConfigurationProperties(prefix = "swagger", ignoreUnknownFields = true)
      @Data
      public class SwaggerProperties {
      
      /**
       * 是否开启swagger,生产环境一般关闭,所以这里定义一个变量
       */
        private Boolean enable;
      
      /**
       * 文档标题
       */
        private String title;
      
      /**
       * 描述
       */
        private String description;
      
      /**
       * 版本号
       */
      private String version;
      
      /**
       * api扫描包路径
       */
        private String[] basePackage;
      
      /**
       * 是否开启head参数
       */
        private Boolean headEnable = false;
      
      /**
       * head参数
       */
        private List<HeadParam> headParams;
      }
      
      1. 一个小类
      @Data
      public class HeadParam {
        private String param;
        private Boolean required = false;
      }
      
      1. swagger配置文件
        import java.util.ArrayList;
        import java.util.List;
        import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
        import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
        import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
        import org.springframework.boot.context.properties.EnableConfigurationProperties;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
      
        import com.google.common.base.Function;
        import com.google.common.base.Optional;
        import com.google.common.base.Predicate;
        import com.google.common.base.Predicates;
      
        import cn.hutool.core.util.ArrayUtil;
        import cn.hutool.core.util.StrUtil;
        import io.swagger.annotations.Api;
        import io.swagger.annotations.ApiOperation;
        import springfox.documentation.RequestHandler;
        import springfox.documentation.builders.ApiInfoBuilder;
        import springfox.documentation.builders.ParameterBuilder;
        import springfox.documentation.builders.PathSelectors;
        import springfox.documentation.builders.RequestHandlerSelectors;
        import springfox.documentation.schema.ModelRef;
        import springfox.documentation.service.ApiInfo;
        import springfox.documentation.service.Parameter;
        import springfox.documentation.spi.DocumentationType;
        import springfox.documentation.spring.web.plugins.Docket;
        import springfox.documentation.swagger2.annotations.EnableSwagger2;
      
      
      /**
       * @ConditionalOnClass({Docket.class, ApiInfoBuilder.class}) 当存在Docket和ApiInfoBuilder类的时候才加    载Bean;
       * @ConditionalOnMissingClass 不存在某个类的时候才会实例化Bean;
       * @ConditionalOnProperty(prefix = "swagger", value = "enable", matchIfMissing = true)
       * 当存在swagger为前缀的属性,才会实例化Bean;
       * @ConditionalOnMissingBean 当不存在某个Bean的时候才会实例化;
       */
      
        @Configuration
        @EnableSwagger2
        @ConditionalOnClass({Docket.class, ApiInfoBuilder.class})
        @ConditionalOnProperty(prefix = "swagger", value = "enable", matchIfMissing = true)
        @EnableConfigurationProperties(SwaggerProperties.class)
      public class SwaggerConfig {
      
          // 定义分隔符,配置Swagger多包
          private static final String splitor = ";";
      
            @Bean
            @ConditionalOnMissingBean
            public SwaggerProperties swaggerProperties() { 
                return new SwaggerProperties();
            }
      
          @Bean
          public Docket api() {
              SwaggerProperties properties = swaggerProperties();
          
              // header参数设置
              List<Parameter> headParams = new ArrayList<>();
              List<HeadParam> hpList = properties.getHeadParams();
              if (properties.getHeadEnable() == true && hpList.size() > 0) {
                  for (HeadParam hp : hpList) {
                      ParameterBuilder pb = new ParameterBuilder();
                      headParams.add(
                          pb.name(hp.getParam())
                            .modelRef(new ModelRef("string"))
                            .parameterType("header")
                            .required(hp.getRequired())
                            .build());
                  }
              }
          
          // 扫描的包路径
          String[] basePackageList = properties.getBasePackage();
          String basePackage = "xyz.2020555";
          if (basePackageList != null && basePackageList.length > 0) {
              basePackage += ";" + ArrayUtil.join(basePackageList, ";");
          }
          
          return new Docket(DocumentationType.SWAGGER_2)
                  // 开关
                  .enable(properties.getEnable() == null?false:properties.getEnable()) 
                  .select()
                  // 指定扫描1个包
                  // .apis(RequestHandlerSelectors.basePackage("com.test.controller"))
                  // 扫描多包
                  .apis(scanBasePackage(basePackage))
                  // 只有标记了@Api的类方法才会暴露出给swagger
                  .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                  // 只有标记了@ApiOperation的方法才会暴露出给swagger
                  .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                  // 匹配路径
                  .paths(PathSelectors.any())
                  .build()
                  .globalOperationParameters(headParams)
                  .apiInfo(apiInfo(properties));
      }
      
      private ApiInfo apiInfo(SwaggerProperties properties) {
          return new ApiInfoBuilder()
                  .title(properties.getTitle())
                  .description(properties.getDescription())
                  .version(properties.getVersion())
                  .build();
      }
      
      
      /**
       * 切割扫描的包生成Predicate<RequestHandler>
       */
      public static Predicate<RequestHandler> scanBasePackage(final String basePackage) {
          if (StrUtil.isBlank(basePackage)) {
              throw new NullPointerException("basePackage不能为空,多个包扫描使用" + splitor + "分隔");
          }
          String[] controllerPack = basePackage.split(splitor);
          Predicate<RequestHandler> predicate = null;
          for (int i = controllerPack.length - 1; i >= 0; i--) {
              String strBasePackage = controllerPack[i];
              if (StrUtil.isNotBlank(strBasePackage)) {
                  Predicate<RequestHandler> tempPredicate = (Predicate<RequestHandler>) RequestHandlerSelectors
                          .basePackage(strBasePackage);
                  predicate = predicate == null ? tempPredicate : Predicates.or(tempPredicate, predicate);
              }
          }
          if (predicate == null) {
              throw new NullPointerException("basePackage配置不正确,多个包扫描使用" + splitor + "分隔");
          }
              return predicate;
          }
      
      }
      

    至此,公共模块中swagger配置这样的:

    image.png
    因为要在yml文件中配置swagger,所以在公共模块META-INF中加一些元数据:additional-spring-configuration-metadata.json,非必须的,我用的eclipse,不想看见黄色感叹号,还能有提示
    {"properties": [
      {
        "name": "swagger.enable",
        "type": "java.lang.Boolean",
        "description": "是否开启swagger'"
      },
      {
        "name": "swagger.title",
        "type": "java.lang.String",
        "description": "文档标题'"
      },
      {
        "name": "swagger.version",
        "type": "java.lang.String",
        "description": "版本号'"
      },
      {
        "name": "swagger.description",
        "type": "java.lang.String",
        "description": "描述'"
      },
      {
        "name": "swagger.head-enable",
        "type": "java.lang.Boolean",
        "description": "是否开启head参数'"
      },
      {
        "name": "swagger.head-params",
        "type": "java.util.List",
        "description": "head参数'"
      },
      {
        "name": "swagger.base-package",
        "type": "java.util.List",
        "description": "api扫描包路径"
      }
    ]}
    

    我放到这了:


    image.png

    配置,到这就完成了。

    4. 使用

    使用时,在其他微服务中导入公共模块的jar包,然后在yml文件中配置。

    # 5.swagger
    swagger: 
      enable: true
      title: ${spring.application.name}
      version: 1.0
      base-package: 
        - com.test.controller
      description: 访问地址:http://192.168.50.30:${server.port}${server.servlet.context-path}
      head-enable: true
      head-params:  
        - param: token1
          required: true
        - param: token2
          required: false
    

    自己封装自己用,可以自嗨了。。。。。。。

    相关文章

      网友评论

          本文标题:Springboot多模块项目,在公共模块整合Swagger2

          本文链接:https://www.haomeiwen.com/subject/igecgktx.html