Swagger

1、Swagger的诞生

前后端分离

  • 后端团队:

    • 控制层、服务层、数据访问层

  • 前端团队:

    • 控制层、视图层

    • 伪造测试数据,数据类型为json,不需要后端提供数据,前端工程也能正常运行

  • 前后端交互:

    • 通过API接口,后端提供正确的json类型的数据以及能访问这个数据的API接口,前端通过接口访问数据

  • 前后端分离产生的问题:

    • 前后端集成联调,需求发生变化无法做到即时协商,及时解决

  • 问题解决办法:

    • 后端:

      提供接口,实时更新最新的消息及改动

    • 前端:

      测试后端生成的API是否可以连接成功

    • 前端测试工具:

      • postman

      • Swagger

        世界上最流行的API框架

        Restful API文档在线自动生成工具

        API文档与API定义实时同步更新

        直接运行,可以在线测试API

 

2、SpringBoot集成Swagger

  • 新建一个SpringBoot的web项目

  • 导入swagger的依赖

    <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger-ui</artifactId>
       <version>2.9.2</version>
    </dependency>
       
    <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger2</artifactId>
       <version>2.9.2</version>
    </dependency>
  • 编写一个hello工程

    @RestController
    public class HelloController {

       @GetMapping("/hello")
       public String hello(){
           return "hello";
      }
    }
  • 集成Swagger

    @Configuration
    //启动Swagger2的相关功能
    @EnableSwagger2
    public class SwaggerConfig {
    }
  • 测试运行

    启动项目,访问:http://localhost:8080/swagger-ui.html,出现以下页面

 

2.1 Docket构造方法

public Docket(DocumentationType documentationType) {
   //Swagger基本信息
   this.apiInfo = ApiInfo.DEFAULT;
   //Swagger文档的分组
   this.groupName = "default";
   //Swagger的开关控制
   this.enabled = true;
   this.genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
   this.applyDefaultResponseMessages = true;
   this.host = "";
   this.pathMapping = Optional.absent();
   this.apiSelector = ApiSelector.DEFAULT;
   this.enableUrlTemplating = false;
   this.vendorExtensions = Lists.newArrayList();
   this.documentationType = documentationType;
}

 

 

2.2 配置Swagger的基本信息

  • 1、配置Swagger的Bean实例:Docket

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {

       //配置了Swagger的Docket的Bean实例
       @Bean
       public Docket docket(){
           return new Docket(DocumentationType.SWAGGER_2);
      }
    }
    • 查看ApiInfo的源码:

      public class ApiInfo {
         public static final Contact DEFAULT_CONTACT = new Contact("", "", "");
         public static final ApiInfo DEFAULT;
         private final String version;
         private final String title;
         private final String description;
         private final String termsOfServiceUrl;
         private final String license;
         private final String licenseUrl;
         private final Contact contact;
         private final List<VendorExtension> vendorExtensions;

         /** @deprecated */
         @Deprecated
         public ApiInfo(String title, String description, String version, String termsOfServiceUrl, String contactName, String license, String licenseUrl) {
             this(title, description, version, termsOfServiceUrl, new Contact(contactName, "", ""), license, licenseUrl, new ArrayList());
        }

         //ApiInfo的有参构造方法
         public ApiInfo(String title, String description, String version, String termsOfServiceUrl, Contact contact, String license, String licenseUrl, Collection<VendorExtension> vendorExtensions) {
             this.title = title;
             this.description = description;
             this.version = version;
             this.termsOfServiceUrl = termsOfServiceUrl;
             this.contact = contact;
             this.license = license;
             this.licenseUrl = licenseUrl;
             this.vendorExtensions = Lists.newArrayList(vendorExtensions);
        }

         public String getTitle() {
             return this.title;
        }

         public String getDescription() {
             return this.description;
        }

         public String getTermsOfServiceUrl() {
             return this.termsOfServiceUrl;
        }

         public Contact getContact() {
             return this.contact;
        }

         public String getLicense() {
             return this.license;
        }

         public String getLicenseUrl() {
             return this.licenseUrl;
        }

         public String getVersion() {
             return this.version;
        }

         public List<VendorExtension> getVendorExtensions() {
             return this.vendorExtensions;
        }

         //ApiInfo的默认信息;
         static {
             DEFAULT = new ApiInfo("Api Documentation", "Api Documentation", "1.0", "urn:tos", DEFAULT_CONTACT, "Apache 2.0", "http://www.apache.org/licenses/LICENSE-2.0", new ArrayList());
        }
      }
  • 自定义ApiInfo,并使用

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {

       //自定义ApiInfo
       Contact contact = new Contact("hmx", "", "");
       ApiInfo apiInfo = new ApiInfo(
               "hmx的Swagger笔记",
               "Api 文档",
               "1.0",
               "urn:tos",
               contact,
               "Apache 2.0",
               "http://www.apache.org/licenses/LICENSE-2.0",
               new ArrayList());

       //配置了Swagger的Docket的Bean实例
       @Bean
       public Docket docket(){
           return new Docket(DocumentationType.SWAGGER_2)
              //自定义ApiInfo的使用
                  .apiInfo(apiInfo);
      }
    }
  • 启动项目,访问:http://localhost:8080/swagger-ui.html,出现以下页面

 

2.3 配置Swagger的扫描接口

  • 使用 Docket 的 select() 方法

    • select()源码:

      public ApiSelectorBuilder select() {
         return new ApiSelectorBuilder(this);
      }
    • ApiSelectorBuilder的源码的核心代码如下:

      public class ApiSelectorBuilder {

         //ApiSelectorBuilder.api方式:要扫描的
         public ApiSelectorBuilder apis(Predicate<RequestHandler> selector) {
             this.requestHandlerSelector = Predicates.and(this.requestHandlerSelector, selector);
             return this;
        }

         //ApiSelectorBuilder.paths方式:要过滤的
         public ApiSelectorBuilder paths(Predicate<String> selector) {
             this.pathSelector = Predicates.and(this.pathSelector, selector);
             return this;
        }

         public Docket build() {
             return this.parent.selector(new ApiSelector(this.combine(this.requestHandlerSelector, this.pathSelector), this.pathSelector));
        }

         private Predicate<RequestHandler> combine(Predicate<RequestHandler> requestHandlerSelector, Predicate<String> pathSelector) {
             return Predicates.and(requestHandlerSelector, this.transform(pathSelector));
        }

         private Predicate<RequestHandler> transform(final Predicate<String> pathSelector) {
             return new Predicate<RequestHandler>() {
                 public boolean apply(RequestHandler input) {
                     return Iterables.any(input.getPatternsCondition().getPatterns(), pathSelector);
                }
            };
        }
      }
  • 1、ApiSelectorBuilder.api方式

    • RequestHandlerSelectors 类源码的核心代码如下:

      public class RequestHandlerSelectors {
         private RequestHandlerSelectors() {
             throw new UnsupportedOperationException();
        }

         //扫描任何包
         public static Predicate<RequestHandler> any() {
             return Predicates.alwaysTrue();
        }

         //所有包都不扫描
         public static Predicate<RequestHandler> none() {
             return Predicates.alwaysFalse();
        }

         //扫描有指定注解的方法
         public static Predicate<RequestHandler> withMethodAnnotation(final Class<? extends Annotation> annotation) {
             return new Predicate<RequestHandler>() {
                 public boolean apply(RequestHandler input) {
                     return input.isAnnotatedWith(annotation);
                }
            };
        }

         //扫描有指定注解的类
         public static Predicate<RequestHandler> withClassAnnotation(final Class<? extends Annotation> annotation) {
             return new Predicate<RequestHandler>() {
                 public boolean apply(RequestHandler input) {
                     return (Boolean)RequestHandlerSelectors.declaringClass(input).transform(RequestHandlerSelectors.annotationPresent(annotation)).or(false);
                }
            };
        }

         //扫描指定包
         public static Predicate<RequestHandler> basePackage(final String basePackage) {
             return new Predicate<RequestHandler>() {
                 public boolean apply(RequestHandler input) {
                     return (Boolean)RequestHandlerSelectors.declaringClass(input).transform(RequestHandlerSelectors.handlerPackage(basePackage)).or(true);
                }
            };
        }
         
      }
    • 在SwaggerConfig中实现

      @Bean
      public Docket docket(){
         return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo)
            .select()
             //五种方式选其一
            .apis(RequestHandlerSelectors.basePackage(""))
            .apis(RequestHandlerSelectors.any())
            .apis(RequestHandlerSelectors.none())
            .apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class))
            .apis(RequestHandlerSelectors.withClassAnnotation(Configuration.class))
            .build();
      }
  • 2、ApiSelectorBuilder.paths方式

    • PathSelectors类的源码如下:

      public class PathSelectors {
         private PathSelectors() {
             throw new UnsupportedOperationException();
        }

      //过滤所有包
         public static Predicate<String> any() {
             return Predicates.alwaysTrue();
        }

         //所有包都不过滤
         public static Predicate<String> none() {
             return Predicates.alwaysFalse();
        }

         //正则表达式
         public static Predicate<String> regex(final String pathRegex) {
             return new Predicate<String>() {
                 public boolean apply(String input) {
                     return input.matches(pathRegex);
                }
            };
        }

         //路径匹配
         public static Predicate<String> ant(final String antPattern) {
             return new Predicate<String>() {
                 public boolean apply(String input) {
                     AntPathMatcher matcher = new AntPathMatcher();
                     return matcher.match(antPattern, input);
                }
            };
        }
      }
    • 在SwaggerConfig中实现

      @Bean
      public Docket docket(){
         return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo)
            .select()
             //4中方式选其一
            .paths(PathSelectors.none())
            .paths(PathSelectors.any())
            .paths(PathSelectors.regex(""))
            .paths(PathSelectors.ant(""))
            .build();
      }

 

2.4 配置Swagger的开关

  • 使用 Docket 里的 Enable 方法

  • 在SwaggerConfig中实现

    • true:表示开启

    • false表示关闭

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {

       @Bean
       public Docket docket(){
           return new Docket(DocumentationType.SWAGGER_2)
                  .enable(true);
      }
    }
  • enable = false 时,启动项目,访问:http://localhost:8080/swagger-ui.html,出现以下页面

  • 在开发时,开启Swagger,上线时,关闭Swagger

    • 1、配置多环境

      spring:
      profiles:
        active: dev
      ---
      spring:
      profiles: dev

      server:
      port: 8081
      ---
      spring:
      profiles: test

      server:
      port: 8082
      ---
      spring:
      profiles: prod

      server:
      port: 8083
    • 2、获取项目的环境并且运用

      @Configuration
      @EnableSwagger2
      public class SwaggerConfig {

         //配置了Swagger的Docket的Bean实例
         @Bean
         public Docket docket(Environment environment){

             //设置要显示Swagger的环境
             Profiles profiles = Profiles.of("dev","test");
             //通过environment.acceptsProfiles(profiles)判断当前是否处于我们设定的环境中
             boolean acceptsProfiles = environment.acceptsProfiles(profiles);

             return new Docket(DocumentationType.SWAGGER_2)
                    .enable(acceptsProfiles);
        }

      }
    • 3、启动项目测试

      • 当前环境是dev,启动可以正常显示Swagger

      • 改动环境在prod,再次启动项目,Swagger显示不出来

 

2.5 配置API文档的分组

  • Docket 的 groupName方法

  • 在SwaggerConfig中实现

    @Bean
    public Docket docket(){
       return new Docket(DocumentationType.SWAGGER_2)
          .apiInfo(apiInfo)
          .groupName("hmx");
    }
  • 启动项目,查看效果:

  • 分多个组协同开发

    • 在SwaggerConfig中实现

    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
       
       @Bean
       public Docket docket(){
           return new Docket(DocumentationType.SWAGGER_2)
                  .groupName("hmx");
      }

       @Bean
       public Docket docketAAA(){
           return new Docket(DocumentationType.SWAGGER_2)
                  .groupName("AAA");
      }

       @Bean
       public Docket docketBBB(){
           return new Docket(DocumentationType.SWAGGER_2)
                  .groupName("BBB");
      }
    }
  • 启动项目,查看效果

    • 选择框里有三个分组

    • 点击分组名可以调到对应的分组

 

2.6 实体类配置

  • 1、创建实体类

    public class User {
       public String userName;
       public String passWord;
    }
  • 2、在Controller中配置接口

    @RestController
    public class HelloController {

       //只要接口中的返回值存在实体类,就会被Swagger扫描
       @PostMapping(value = "/user")
       public User user(){
           return new User();
      }
    }
  • 3、启动项目测试

  • 4、给实体类加注释

    @ApiModel("用户实体类")
    public class User {
       @ApiModelProperty("用户名")
       public String userName;
       @ApiModelProperty("密码")
       public String passWord;
    }
  • 5、再次启动项目测试

 

2.7 Swagger测试

测试过程如下:

 

2.8 Swagger 的 API注解

  • 给实体类加注释

    • 类:@ApiModel("用户实体类")

    • 属性:@ApiModelProperty("用户名")

  • 给接口加注释

    • Controller中的方法:@ApiOperation("user接口")

    • 方法的参数:@ApiParam("用户名")

原文地址:https://www.cnblogs.com/LittleSkinny/p/13697083.html