Loading... 微服务开发中想将`Spring-Cloud-Gateway`网关聚合knife4j,形成一个统一入口方便查阅的开发辅助接口文档,并且将Swagger抽取成一个公共模块,那么我们可以参考以下的做法 > 约定: > > Java Version:11.0.24 > > Spring Boot:2.7.18 > > knife4j:4.4.0 ## Swagger公共模块抽取 ### 依赖 ```java <dependencies> <!-- SpringBoot Web (支持构建Web应用程序,包括Spring MVC和内嵌的Servlet容器) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Knife4j API 小刀注解依赖 --> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-openapi2-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.6</version> </dependency> <!-- SpringBoot Actuator (支持集成Actuator,用于监控和管理应用程序) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- Java Bean Validation API --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <!-- Lombok 辅助器 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> ``` ### 定义配置Swagger Properties ```java package com.if010.common.swagger.properties; import lombok.*; import org.springframework.boot.context.properties.ConfigurationProperties; import java.io.Serializable; /** * Swagger Properties配置信息实体类 * @author Kim同学 */ @Data @NoArgsConstructor @ToString @ConfigurationProperties(prefix = "swagger") public class SwaggerConfigProperties implements Serializable { //配置 API (com.xxx.controller) 扫描路径 public String controllerPath; //配置 API 文档标题 public String title; //配置 API 版本信息 public String version; //配置 API 文档描述 public String description; //配置 API 文档许可 描述 或 协议 public String license; //配置 API 文档许可 描述 或 协议 的 URL public String licenseUrl; //配置 API 文档 联系人 信息 public String contactName; //配置 API 文档 联系人 主页 URL public String contactUrl; //配置 API 文档 联系人 邮箱 public String contactEmail; } ``` ### 定义配置Swagger Config ```java package com.if010.common.swagger.config; import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; import com.if010.common.swagger.properties.SwaggerConfigProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType; import org.springframework.boot.actuate.endpoint.ExposableEndpoint; import org.springframework.boot.actuate.endpoint.web.*; import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier; import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier; import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * Swagger 配置类 * @author Kim同学 */ @Slf4j @Configuration @EnableSwagger2WebMvc @EnableKnife4j @ConditionalOnClass({Docket.class, ApiInfoBuilder.class}) @EnableConfigurationProperties(SwaggerConfigProperties.class) @Import(BeanValidatorPluginsConfiguration.class) public class SwaggerConfig { @Autowired SwaggerConfigProperties swaggerConfigProperties; private ApiInfo apiInfoBuilder() { ApiInfo apiInfoBuild = new ApiInfoBuilder() // api文档名称 .title(swaggerConfigProperties.getTitle()) // api文档描述 .description(swaggerConfigProperties.getDescription()) // api文档版本 .version(swaggerConfigProperties.getVersion()) // api作者信息 .contact( new Contact( swaggerConfigProperties.getContactName(), swaggerConfigProperties.getContactUrl(), swaggerConfigProperties.getContactEmail() ) ) // api文档许信息 .license(swaggerConfigProperties.getLicense()) // api文档许信息链接 .licenseUrl(swaggerConfigProperties.getLicenseUrl()) .build(); return apiInfoBuild; } @Bean(value = "defaultApi2") @ConditionalOnClass(SwaggerConfigProperties.class) public Docket defaultApi2() { log.info("swaggerInfo:{}", swaggerConfigProperties.getControllerPath()); // 构建API文档 文档类型为swagger2 return new Docket(DocumentationType.SWAGGER_2).select() // 配置 API 扫描路径 以及 过滤规则(any代表所有路径) .apis(RequestHandlerSelectors.basePackage(swaggerConfigProperties.getControllerPath())).paths(PathSelectors.any()) // 配置 API 的基本信息 .build().apiInfo(apiInfoBuilder()); } /** * 增加如下配置可解决Spring Boot 6.x 与Swagger 3.0.0 不兼容问题 **/ @Bean public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties, Environment environment) { List<ExposableEndpoint<?>> allEndpoints = new ArrayList(); Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints(); allEndpoints.addAll(webEndpoints); allEndpoints.addAll(servletEndpointsSupplier.getEndpoints()); allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints()); String basePath = webEndpointProperties.getBasePath(); EndpointMapping endpointMapping = new EndpointMapping(basePath); boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment, basePath); return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath), shouldRegisterLinksMapping, null); } private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment, String basePath) { return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT)); } } ``` 因为是starter模块,可能他人的项目目录和starter模块的目录不一致,导致加载不到SwaggerConfig类,我们需要使用`spring.factories`把SwaggerConfig类装载到Spring容器,在resources/META-INF/spring添加`org.springframework.boot.autoconfigure.AutoConfiguration.imports`文件 ![SwaggerAutoConfiguration](https://resource.if010.com/SpringCloud_knife4j_Conformity_01.png) 到目前为止,Swagger的抽取工作就已经算是全部完成了,接下来我们就可以在业务模块中引入进行测试使用了 ### 引用 首先我们需要将Swagger公共依赖添加到业务模块的pom文件当中 ```java <dependencies> <!-- If010 Common Swagger --> <dependency> <groupId>com.if010</groupId> <artifactId>if010-common-swagger</artifactId> </dependency> </dependencies> ``` 接下来,在`application.yml`定义Swagger的配置信息 ```yaml swagger: # 配置 API 扫描路径 controllerPath: com.if010.system.controller # 配置 API 文档标题 title: 系统管理模块接口文档 # 配置 API 版本信息 version: 1.0.0 # 配置 API 文档描述 description: 系统管理模块 # 配置 API 文档许可 描述 license: Copyright © 2018 If010工作室™ # 配置 API 文档许可 描述 URL licenseUrl: https://if010.com # 配置 API 文档 联系人 contact-name: Kim同学 # 配置 API 文档 联系人 主页 URL contact-url: www.if010.com # 配置 API 文档 联系人 邮箱 contact-email: kim@if010.com ``` 到此结束,紧接着我们就可以启动业务服务模块,访问:`http://{service.host}:{service.port}/doc.html`,看看效果啦~~ ![接口文档页面结果](https://resource.if010.com/SpringCloud_knife4j_Conformity_02.png) ## 网关聚合knife4j ### 依赖 ```java <dependencies> # 网关所需要的依赖这里就不进行展示啦,给你们节省一点流量 ..... <!-- Knife4j API 小刀注解依赖 --> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-gateway-spring-boot-starter</artifactId> </dependency> </dependencies> ``` ### 定义application.yml文件 ```yaml spring: application: # 应用名称 name: if010-gateway profiles: # 环境配置 active: dev cloud: # Nacos注册中心配置 nacos: # Nacos的认证登录用户账户 username: admin # Nacos的认证登录用户密码 password: 123456 discovery: # 服务注册地址 server-addr: 127.0.0.1:8848 config: # 配置中心地址 server-addr: 127.0.0.1:8848 # 配置文件格式 file-extension: yml # 共享配置 shared-configs: - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} - application-${spring.profiles.active}-nacos.${spring.cloud.nacos.config.file-extension} - ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} # 超时时间 timeout: 3000 # 路由配置 gateway: routes: - id: system-service uri: lb://if010-system predicates: - Path=/system-service/** filters: # StripPrefix 是 url 过滤器,1表示请求转发给后端业务服务时,去掉上面Path里从左往右的第1个路径,即system-service - StripPrefix=1 # knife4j的网关聚合配置 文档地址:http://{gateway.host}:{gateway.port}/doc.html knife4j: # 聚合swagger文档 gateway: # 是否开启Knife4j网关聚合功能(生产环境不建议开启) enabled: true # 排序规则(tag/operation排序自4.2.0版本新增) # 取值:alpha-默认排序规则,官方swagger-ui默认实现,order-Knife4j提供的增强排序规则,开发者可扩展x-order,根据数值来自定义排序 tags-sorter: order operations-sorter: order # 指定聚合的策略(默认手动配置(manual),服务发现(discover)) strategy: manual discover: # 是否开启服务发现模式的配置 enabled: false # 指定版本号(swagger2|openapi3) version: swagger2 # 需要排除的微服务(eg:网关服务) excluded-services: - if010-gateway # Swagger2个性化配置 swagger2: url: /v2/api-docs?group=default # 个性化定制的部分子服务分组情况 routes: - name: 系统管理模块 # 服务名 service-name: system-service # 真实子服务访问url地址-提供OpenAPI的文档 url: /system-service/v2/api-docs?group=default # 路由前缀,兼容OpenAPI3规范在聚合时丢失contextPath属性的异常情况,由开发者自己配置contextPath,Knife4j的前端Ui做兼容处理,与url属性独立不冲突,仅OpenAPI3规范聚合需要,OpenAPI2规范不需要设置此属性,默认为(apiPathPrefix) context-path: / # 排序 order: 1 ``` 到此为止,网关聚合knife4j工作就结束了,操作不涉及代码,全都是配置相关,因为个人严重的洁癖问题`discover`自动发现并没有开启,想省事偷懒的可以开起来,可以大大减少手动配置的工作 访问:`http://{gateway.host}:{gateway.port}/doc.html`,看看效果啦~~ ![接口文档页面结果](https://resource.if010.com/SpringCloud_knife4j_Conformity_03.png) 最后修改:2024 年 10 月 12 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 -