微服务实战(七) 聚合OpenAPI文档

  • Post author:
  • Post category:其他




微服务实战(六) 基于 Knife4jAggregationDesktop实现聚合OpenAPI文档

官方文档:https://doc.xiaominfo.com/knife4j/resources/aggregation-introduction.html


  • swagger-bootstrap-ui



    springfox-swagger

    的增强UI实现,为Java开发者在使用Swagger的时候,能拥有一份简洁、强大的接口文档体验

  • Knife4j

    是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是

    swagger-bootstrap-ui

    ,取名kni4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍!

  • Knife4jAggregation

    是给Spring Boot的web系统赋能,拥有聚合OpenAPI文档的能力

  • Knife4jAggregationDesktop

    是一款基于聚合组件

    Knife4jAggregation

    特性的独立部署的聚合OpenAPI文档软件,脱离Spring、Spring Boot技术架构体系,开发者下载后独立部署启动。开发者可以理解为能够渲染OpenAPI规范的独立文档应用



自定义swagger模块




模块结构

├─src
│  └─main
│      ├─java
│      │  └─com.sunnyws.common.swagger
│      │             ├── annotation
│      │             │      └── EnableKnife4jSwagger.java
│      │             └── config
│      │                     ├── SwaggerAutoConfiguration.java
│      │                     └── SwaggerProperties.java
│      └─resources




引入依赖

  • 引入

    knife4j-spring-boot-starter



    swagger-models``knife4j-micro-spring-boot-starter
  • 引入

    knife4j-spring-boot-starter

    则每个项目都有单独的swagger文档,不影响Knife4jAggregationDesktop进行聚合使用
  • 引入

    swagger-models``knife4j-micro-spring-boot-starter

    只是剔除了

    knife4j-spring-boot-starter

    的前端部分,每个项目无法通过页面单独查看swagger文档,只能通过Knife4jAggregationDesktop聚合查看
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.2</version>
</dependency>

<dependency>
    <groupId>io.swagger</groupId>
    <artifactId>swagger-models</artifactId>
    <version>1.5.22</version>
</dependency>

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-micro-spring-boot-starter</artifactId>
    <version>3.0.2</version>
</dependency>




完整依赖

    <properties>
        <knife4j.swagger.version>3.0.2</knife4j.swagger.version>
        <swagger.version>1.5.22</swagger.version>
    </properties>


    <dependencies>
        <!-- SpringBoot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

<!--        <dependency>-->
<!--            <groupId>com.github.xiaoymin</groupId>-->
<!--            <artifactId>knife4j-spring-boot-starter</artifactId>-->
<!--            <version>${knife4j.swagger.version}</version>-->
<!--        </dependency>-->
        
        <!-- knife4j swagger -->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>${swagger.version}</version>
        </dependency>

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-micro-spring-boot-starter</artifactId>
            <version>${knife4j.swagger.version}</version>
        </dependency>
    </dependencies>




自定义swagger配置

  • 除了通过自定义属性,对swagger必要参数进行设置,也可以通过knife4j增强特性对knife4j swagger前端页面一些参数进行修改,这里就不详细说,可以通过官方文档学习。
  • 官方文档:https://doc.xiaominfo.com/knife4j/documentation/
@Data
@Component
@ConfigurationProperties("swagger")
public class SwaggerProperties {
    /**
     * 是否开启swagger
     */
    private Boolean enabled = true;

    /**
     * swagger会解析的包路径
     **/
    private String basePackage = "";


    /**
     * group
     **/
    private String groupName = "default";

    /**
     * swagger会解析的url规则
     **/
    private List<String> basePath = new ArrayList<>();

    /**
     * 在basePath基础上需要排除的url规则
     **/
    private List<String> excludePath = new ArrayList<>();

    /**
     * 标题
     **/
    private String title = "swagger";

    /**
     * 描述
     **/
    private String description = "swagger document";

    /**
     * 版本
     **/
    private String version = "1.0";

    /**
     * 许可证
     **/
    private String license = "";

    /**
     * 许可证URL
     **/
    private String licenseUrl = "";

    /**
     * 服务条款URL
     **/
    private String termsOfServiceUrl = "";

    /**
     * host信息
     **/
    private String host = "";

    /**
     * 联系人信息
     */
    private Contact contact = new Contact();


    @Data
    public static class Contact {
        /**
         * 联系人
         **/
        private String name = "";
        /**
         * 联系人url
         **/
        private String url = "";
        /**
         * 联系人email
         **/
        private String email = "";

    }

}
@EnableSwagger2
@EnableAutoConfiguration
public class SwaggerAutoConfiguration {
    /**
     * 默认的排除路径,排除Spring Boot默认的错误处理路径和端点
     */
    private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");

    private static final String BASE_PATH = "/**";

    @Bean
    public SwaggerProperties swaggerProperties()
    {
        return new SwaggerProperties();
    }

    @Bean
    @Order(value = 1)
    public Docket api(SwaggerProperties swaggerProperties) {
        // base-path处理
        if (swaggerProperties.getBasePath().isEmpty()) {
            swaggerProperties.getBasePath().add(BASE_PATH);
        }

        return new Docket(DocumentationType.SWAGGER_2)
                .enable(swaggerProperties.getEnabled())
                .host(swaggerProperties.getHost())
                .apiInfo(apiInfo(swaggerProperties)).select()
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                .paths(PathSelectors.any())
                .build()
                .groupName(swaggerProperties.getGroupName())
                .securityContexts(CollectionUtils.newArrayList(securityContext(),securityContext1()))
                .securitySchemes(CollectionUtils.<SecurityScheme>newArrayList(apiKey(),apiKey1()));
    }

    private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
        return new ApiInfoBuilder()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .license(swaggerProperties.getLicense())
                .licenseUrl(swaggerProperties.getLicenseUrl())
                .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
                .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
                .version(swaggerProperties.getVersion())
                .build();
    }

    /**
     * 安全模式,这里指定token通过Authorization头请求头传递
     */
    private ApiKey apiKey() {
        return new ApiKey("BearerToken", "Authorization", "header");
    }
    private ApiKey apiKey1() {
        return new ApiKey("BearerToken1", "Authorization-x", "header");
    }

    /**
     * 安全上下文
     */
    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex("/.*"))
                .build();
    }
    private SecurityContext securityContext1() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth1())
                .forPaths(PathSelectors.regex("/.*"))
                .build();
    }
    /**
     * 默认的全局鉴权策略
     *
     * @return
     */
    List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return CollectionUtils.newArrayList(new SecurityReference("BearerToken", authorizationScopes));
    }
    List<SecurityReference> defaultAuth1() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return CollectionUtils.newArrayList(new SecurityReference("BearerToken1", authorizationScopes));
    }

}




自定义注解

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({ SwaggerAutoConfiguration.class })
public @interface EnableKnife4jSwagger {

}




引用Swagger




引入依赖

  • 版本根据自己的项目定义
  • 使用Nacos注册中心,以便Knife4jAggregationDesktop+Nacos实现聚合
<dependency>
    <groupId>sunnyws.com</groupId>
    <artifactId>sunnyws-common-swagger</artifactId>
</dependency>
<!-- SpringCloud Ailibaba Nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>




添加配置

详细配置查看自定义的

SwaggerProperties.java

server:
  port: 9001
spring:
  application:
    name: sunnyws-service-example1
  profiles:
    active: dev
  cloud:
    nacos:
      discovery:
        server-addr: 172.16.220.50:8848
        namespace: e90d261b-9c05-4bcb-b99f-b419d952737a

swagger:
  enabled: true
  basePackage: com.sunnyws.example1.controller
  title: example1 swagger
  description: <div style='font-size:14px;color:red;'>swagger-bootstrap-ui-demo RESTful APIs</div>
  version: 1.0
  termsOfServiceUrl: test.cn
  groupName: default
  contact:
    name:  test
    url:   test.cn
    email: test@xx.com




启动类添加注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableKnife4jSwagger
public class ServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceApplication.class, args);
    }
}




Knife4jAggregationDesktop




安装

  • 下载地址:https://gitee.com/xiaoym/knife4j/attach_files


Linux环境

#bin目录下的startup.sh文件赋予可执行权限
chmod a+x startup.sh

#启动
./sh startup.sh




修改配置

#进入data下ROOT目录下添加配置,当然也可根据官方文档 在ROOT外新建配置目录 进行配置
cd  ./data/ROOT
#删除初始disk配置示例
rm ./*
#创建Nacos模式配置
touch  nacos.properties
#修改配置
vim  ./nacos.properties


#根据Nacos配置和服务名  修改添加如下配置
knife4j.nacos.serviceUrl=http://172.16.220.50:8848/nacos/
knife4j.nacos.routes[0].name=测试一
knife4j.nacos.routes[0].serviceName=sunnyws-service-example1
knife4j.nacos.routes[0].location=/v2/api-docs?group=default
knife4j.nacos.routes[0].namespaceId:e90d261b-9c05-4bcb-b99f-b419d952737a
knife4j.nacos.routes[1].name=测试二 
knife4j.nacos.routes[1].serviceName=sunnyws-service-example2
knife4j.nacos.routes[1].location=/v2/api-docs?group=default
knife4j.nacos.routes[1].namespaceId:e90d261b-9c05-4bcb-b99f-b419d952737a
#开启认证
#knife4j.basicAuth.enable=true
#knife4j.basicAuth.username=nacos
#knife4j.basicAuth.password=1234




访问页面


  • 默认端口

    :18006

  • 网址

    :http://ip:18006/doc.html

作者: SunnyWs

链接:

https://sunnyws.com/posts/ec81c193/


来源: SunnyWs’Blog