# spring-boot-swagger-starter-test **Repository Path**: fengsoshuai/spring-boot-swagger-starter-test ## Basic Information - **Project Name**: spring-boot-swagger-starter-test - **Description**: 自定义springboot-swagger的starter,基于java17和springboot3.x - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-05-11 - **Last Updated**: 2024-05-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 自定义实现 Java17+SpringBoot3+Knife4j Starter ## 前言 一直以来,在接口文档这块没怎么尝试过比较新的技术点,使用的都是`swagger2` 和 低版本的 `knife4j`。 本次就研究下在高版本的情况下,基于`swagger`的接口文档有什么变化。 > **本文基于以下环境:** > > | 组件 | 版本 | > | -------------------------------------------- | ----- | > | Java | 17 | > | SpringBoot | 3.2.5 | > | knife4j-openapi3-jakarta-spring-boot-starter | 4.5.0 | ## 正文 ### 1 创建starter项目 创建一个Maven类型的SpringBoot项目,作为starter组件的开发。 #### 1.1 依赖文件 在`Maven`项目中,使用`pom.xml`文件来管理依赖。这里列举以下在starter项目中,使用到的依赖坐标。 此处指定了Java版本、Maven编译Java代码时使用的Java版本,并切设置项目的编码格式为`UTF-8`格式。 ```xml 17 17 17 UTF-8 UTF-8 3.2.5 4.5.0 org.springframework.boot spring-boot-starter com.github.xiaoymin knife4j-openapi3-jakarta-spring-boot-starter ${knife4j-openapi3-jakarta-version} jakarta.servlet jakarta.servlet-api org.springframework.boot spring-boot-autoconfigure org.springframework spring-webmvc org.springframework.boot spring-boot-configuration-processor true compile org.projectlombok lombok true org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import ``` #### 1.2 配置信息 因为这个starter组件是基于`SpringBoot3.x`开发的,所以在自定义starter时,使用新的写法,不在直接使用`spring.factories`文件对自动配置类进行配置。 在`resources`目录下,创建目录 `META-INF/spring`,然后创建名为`org.springframework.boot.autoconfigure.AutoConfiguration.imports`的文件备用。 ### 2 自定义starer代码开发 自定义starter的开发,代码量不多,主要是一个自动配置类和配置字段的定义。 #### 2.1 配置字段的定义 ```java package org.feng.basic.swagger.properties; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; /** * Swagger 配置属性 * * @author feng */ @Data @ConfigurationProperties(prefix = SwaggerProperties.PREFIX) public class SwaggerProperties { public static final String PREFIX = "swagger.config"; private String title; private String version; private String description; private String termsOfService; private String licenseName; private String licenseUrl; private Contact contact; @Data public static class Contact { private String name; private String url; private String email; } } ``` #### 2.2 自动配置类 使用注解 `ConditionalOnProperty` 来指定是否进行配置bean的加载。 主要条件是 `knife4j.enable=true`,当满足条件时,配置类中的内容生效。 除此之外,在文件`org.springframework.boot.autoconfigure.AutoConfiguration.imports` 中,添加自动配置类的全名(包名+类名)。 比如,我项目中的自动配置类会配置为:`org.feng.basic.swagger.SwaggerAutoConfiguration`。 ```java package org.feng.basic.swagger; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.info.License; import org.feng.basic.swagger.properties.SwaggerProperties; import org.springdoc.core.customizers.GlobalOpenApiCustomizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; /** * swagger自动配置类 * * @author feng */ @ConditionalOnProperty(prefix = "knife4j", name = "enable", havingValue = SwaggerAutoConfiguration.TRUE, matchIfMissing = true) @EnableConfigurationProperties(SwaggerProperties.class) public class SwaggerAutoConfiguration { public static final String TRUE = "true"; private final SwaggerProperties swaggerProperties; public SwaggerAutoConfiguration(@Autowired SwaggerProperties swaggerProperties) { this.swaggerProperties = swaggerProperties; } /** * 根据@Tag 上的排序,写入x-order * * @return the global open api customizer */ @Bean public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() { return openApi -> { // if (openApi.getTags() != null) { // openApi.getTags().forEach(tag -> { // Map map = new HashMap<>(); // map.put("x-order", ThreadLocalRandom.current().nextInt(0, 100)); // tag.setExtensions(map); // }); // } // if (openApi.getPaths() != null) { // openApi.addExtension("x-test123", "333"); // openApi.getPaths().addExtension("x-abb", ThreadLocalRandom.current().nextInt(0, 100)); // } }; } @Bean public OpenAPI openApi() { return new OpenAPI() .info(new Info() .title(swaggerProperties.getTitle()) .description(swaggerProperties.getDescription()) .version(swaggerProperties.getVersion()) .termsOfService(swaggerProperties.getTermsOfService()) .contact(new Contact().name(swaggerProperties.getContact().getName()) .url(swaggerProperties.getContact().getUrl()) .email(swaggerProperties.getContact().getEmail())) .license(new License().name(swaggerProperties.getLicenseName()).url(swaggerProperties.getLicenseUrl()))); } } ``` ### 3 验证starter 在本地开发时,将 starter 项目进行 `mvn install`打包并上传jar到本地的maven仓库中。 随后,创建一个新项目,在新项目中使用刚刚写好的starter组件。起始就是引入它的maven坐标,这里的版本选择和starter保持一致。 #### 3.1 测试项目的配置 在测试项目中,使用`spring-boot-web`组件。具体的`pom.xml`配置如下: ```xml 17 17 17 UTF-8 UTF-8 3.2.5 org.springframework.boot spring-boot-starter-web org.feng spring-boot-swagger-starter 0.0.1-SNAPSHOT org.projectlombok lombok true org.springframework.boot spring-boot-dependencies ${spring-boot.version} pom import org.apache.maven.plugins maven-compiler-plugin 3.8.1 17 17 UTF-8 org.springframework.boot spring-boot-maven-plugin ${spring-boot.version} org.feng.SpringBootSwaggerStarterTestApplication true repackage repackage ``` #### 3.2 功能配置 application.yml ```yaml server: port: 17813 servlet: context-path: / spring: servlet: multipart: max-file-size: 100MB max-request-size: 100MB application: name: knife4j-spring-boot3-demo springdoc: swagger-ui: path: /swagger-ui.html tags-sorter: alpha #operations-sorter: order api-docs: path: /v3/api-docs # 分组配置,对不同的包进行分组 group-configs: - group: 'test1' display-name: '测试1' paths-to-match: '/**' packages-to-scan: org.feng.test1.controller - group: 'test2' display-name: '测试2' paths-to-match: '/**' packages-to-scan: org.feng.test2.controller default-flat-param-object: true knife4j: enable: true setting: language: zh_cn swagger-model-name: 实体类列表 # 是否在每个Debug调试栏后显示刷新变量按钮,默认不显示 enableReloadCacheParameter: true # 是否开启界面中对某接口的版本控制,如果开启,后端变化后Ui界面会存在小蓝点 enableVersion: true # 针对RequestMapping的接口请求类型,在不指定参数类型的情况下,如果不过滤,默认会显示7个类型的接口地址参数,如果开启此配置,默认展示一个Post类型的接口地址 enableFilterMultipartApis: true # 是否开启动态参数调试功能 enableDynamicParameter: true # 是否显示Footer enableFooter: false enableFooterCustom: true footerCustomContent: Apache License xx | Copyright xxxx [xxxx-xxxx](https://xxxx.com/xxxx) # 自定义主页 enable-home-custom: false home-custom-path: classpath:markdown/README.md documents: - name: 自定义文档1 locations: classpath:markdown/* group: 测试1 - name: 自定义文档2 locations: classpath:markdown1/* group: 测试2 # 启用简单的权限管理,访问接口文档需要登录 basic: enable: true username: abc password: 123 # http://www.knife4j.net/ insight: enable: false service-name: boot3 secret: S6CsnS8AnPVyb8vvChcdXm4R3p6A6KlAISxBg3IIEgk= server: http://localhost:10086 namespace: spring3 swagger: config: title: '${spring.application.name}的在线文档' description: '在线文档' version: 'v1' terms-of-service: '' contact: name: 'feng' email: 'fengsoshuai@163.com' url: '' license-name: '' license-url: '' ``` #### 3.3 测试代码 ##### 3.3.1 实体类 ```java package org.feng.model; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serial; import java.io.Serializable; import java.time.LocalDateTime; /** * TODO * * @author feng */ @Data public class User implements Serializable { @Serial private static final long serialVersionUID = 7250829747040287299L; @Schema(title = "userId", description = "用户ID", defaultValue = "1") private Long id; @Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED) private String name; @Schema(description = "注册日期") private LocalDateTime registerDate; } ``` ##### 3.3.2 控制器1 ```java package org.feng.test1.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.feng.model.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * TODO * * @author feng */ @Tag(name = "test1") @RestController @RequestMapping("/test1") public class Test1Controller { @Operation(summary = "获取详情") @GetMapping("/getOneById") public User getOneDetailById(@RequestParam(required = false) Integer id) { return null; } } ``` ##### 3.3.2 控制器2 ```java package org.feng.test2.controller; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.feng.model.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * TODO * * @author feng */ @Tag(name = "test2") @RestController @RequestMapping("/test2") public class Test2Controller { @Operation(summary = "获取详情") @GetMapping("/getOneById") public User getOneDetailById(@RequestParam(required = false) Integer id) { return null; } } ``` ### 4 效果展示 启动项目后,访问链接:http://localhost:17813/doc.html#/home #### 4.1 主页 ![](imgs/img1.png) #### 4.2 实体类列表 ![](imgs/img2.png) #### 4.3 自定义文档 ![](imgs/img3.png) #### 4.4 接口文档 ![](imgs/img4.png) ## 附录 ### 1 参考文档 + https://doc.xiaominfo.com/docs/quick-start#spring-boot-3 + https://www.mvncenter.com/search/com.github.xiaoymin/knife4j-openapi3-jakarta-spring-boot-starter + https://www.mvncenter.com/search/org.springframework.boot/spring-boot-starter + https://gitee.com/xiaoym/swagger-bootstrap-ui-demo/tree/master/knife4j-spring-boot3-demo + http://www.knife4j.net/ ### 2 注意事项 #### 2.1 测试项目git地址 https://gitee.com/fengsoshuai/spring-boot-swagger-starter-test > 注意:因为starter的代码和配置很少,就不单独建立仓库了。仓库只包含测试项目的代码。starter的代码和配置可以从本文中粘贴出来。 #### 2.2 starter项目目录 ![](imgs/img5.png)