SpringCloud Eureka + Gateway 微服务 聚合 swagger2/knife4j,网上很多使用方法,但因为版本出现各种问题,这里记录一下代码最少的方式。
环境说明
本次配置的是父子工程
- Spring Boot - 2.2.0.RELEASE
- Spring Cloud - Hoxton.RELEASE
- 注册中心 Eureka - 2.2.0.RELEASE
- 网关依赖 GateWay - 2.2.0.RELEASE
父级pom.xml
<modules>
<module>eureka</module>
<module>gateway</module>
<module>system</module>
<module>business</module>
<module>doc</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath />
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 集成 swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.10.5</version>
</dependency>
<!-- 集成 knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.9</version>
</dependency>
# 你自己的依赖包...
</dependencies>
</dependencyManagement>
1、Eureka 模块配置
eureka
依赖包 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
# 你自己的依赖包...
</dependencies>
eureka
配置文件,使用默认端口:8761
# application.properties
# 配置 server
server.port=8761
server.servlet.context-path=/
server.tomcat.uri-encoding=utf-8
# 配置 Eureka
eureka.client.fetch-registry=false
eureka.client.register-with-eureka=false
# 模块名称
spring.application.name=eureka
启动文件 EurekaApplication.java
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
2、GateWay 模块配置
说明一下:GateWay
模块,是为了生产环境使用,Doc
模块,只在本地使用,所以Doc
模块也会集成gateway,所以这一步可以省略!
gateWay
依赖包 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
# 你自己的依赖包...
</dependencies>
gateway
配置文件,路由转发uri
使用负载均衡的方式
# 配置 server
server.port=9000
server.servlet.context-path=/
# 配置 Eureka
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
# 模块名称
spring.application.name=gateway
# 路由转发
spring.cloud.gateway.routes[0].id=system
spring.cloud.gateway.routes[0].uri=lb:://system
#spring.cloud.gateway.routes[0].uri=http://127.0.0.1:9001
spring.cloud.gateway.routes[0].predicates[0].name=Path
spring.cloud.gateway.routes[0].predicates[0].args[0]=/system/**
# 路由转发
spring.cloud.gateway.routes[1].id=business
spring.cloud.gateway.routes[1].uri=lb://business
#spring.cloud.gateway.routes[1].uri=http://127.0.0.1:9002
spring.cloud.gateway.routes[1].predicates[0].name=Path
spring.cloud.gateway.routes[1].predicates[0].args[0]=/business/**
启动文件,添加注解@EnableEurekaClient
# GatewayApplication.java
@EnableEurekaClient
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
3、System 模块配置
system
依赖包 pom.xml
,(business模块依赖一样)
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 集成 swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<!-- 集成 knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
# 你自己的依赖包...
</dependencies>
system
配置文件
注意区分 port
、context-path
# application.properties
# 配置 server
server.port=9001
server.servlet.context-path=/system
# 配置 Eureka
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
# 模块名称
spring.application.name=system
# 配置 knife4j(不写会报错)
knife4j.enable=true
system
配置Java类
注意区分 groupName
、basePackage
# Swagger2Config.java
@Configuration
@EnableSwagger2WebMvc
public class Swagger2Config {
private final OpenApiExtensionResolver openApiExtensionResolver;
@Autowired
public Swagger2Config(OpenApiExtensionResolver openApiExtensionResolver) {
this.openApiExtensionResolver = openApiExtensionResolver;
}
@Bean
public Docket webApiConfig() {
String groupName = "system";
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName(groupName)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.*.system"))
.paths(PathSelectors.any())
.build()
.extensions(openApiExtensionResolver.buildExtensions(groupName));
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("System 接口")
.description("Restful 风格接口")
.version("0.0.1")
.build();
}
}
启动文件,添加注解@EnableEurekaClient
# SystemApplication.java
@EnableEurekaClient
@SpringBootApplication
public class SystemApplication {
public static void main(String[] args) {
SpringApplication.run(SystemApplication.class, args);
}
}
完成以上步骤,子项目集成knife4j
完毕
- 访问:http://127.0.0.1:9001/system/doc.html
- 访问:http://127.0.0.1:9002/business/doc.html
4、Business 模块配置
business
依赖包pom.xml
business
配置文件business
配置Java类- 启动文件,添加注解
这几步参考system
模块配置,此处省略…
5、Doc 模块配置
doc
依赖包 pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 集成 knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
# 你自己的依赖包...
</dependencies>
doc
配置文件,两种格式:properties
、yml
#application.properties
# 配置 Server
server.port=9003
server.servlet.context-path=/
# 配置 Eureka
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
# 模块名称
spring.application.name=doc
spring.cloud.gateway.discovery.locator.enabled=false
spring.cloud.gateway.discovery.locator.lowerCaseServiceId=true
# 路由转发
spring.cloud.gateway.routes[0].id=system
spring.cloud.gateway.routes[0].uri=lb://system
spring.cloud.gateway.routes[0].predicates[0].name=Path
spring.cloud.gateway.routes[0].predicates[0].args[0]=/system/**
# 路由转发
spring.cloud.gateway.routes[1].id=business
spring.cloud.gateway.routes[1].uri=lb://business
spring.cloud.gateway.routes[1].predicates[0].name=Path
spring.cloud.gateway.routes[1].predicates[0].args[0]=/business/**
# 配置 knife4j
knife4j.enableAggregation=true
knife4j.eureka.enable=true
knife4j.eureka.serviceUrl=http://localhost:8761/eureka/
knife4j.eureka.routes[0].name=系统模块
knife4j.eureka.routes[0].serviceName=system
knife4j.eureka.routes[0].servicePath=/system
knife4j.eureka.routes[0].location=/v2/api-docs?group=system
knife4j.eureka.routes[1].name=业务模块
knife4j.eureka.routes[1].serviceName=business
knife4j.eureka.routes[1].servicePath=/business
knife4j.eureka.routes[1].location=/v2/api-docs?group=business
# application.yml
# 配置 server
server:
port: 9003
servlet:
context-path: /
# 配置 Eureka
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
# 配置 Spring
spring:
application:
name: doc
cloud:
gateway:
discovery:
locator:
enabled: false
lowerCaseServiceId: true
routes:
- id: system
uri: lb://system
predicates:
- name: Path
args[0]: /system/**
- id: business
uri: lb://business
predicates:
- name: Path
args[0]: /business/**
# 配置 knife4j
knife4j:
enableAggregation: true
eureka:
enable: true
serviceUrl: http://localhost:8761/eureka/
routes:
- name: 系统模块
serviceName: system
servicePath: /system
location: /v2/api-docs?group=system
- name: 业务模块
serviceName: business
servicePath: /business
location: /v2/api-docs?group=business
doc
配置 创建两个Java类
#SwaggerResourceConfig.java
@Component
@Primary
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
private static final Logger LOG = LoggerFactory.getLogger(SwaggerResourceConfig.class);
// swagger2默认后缀
private static final String Swagger2URL = "/v2/api-docs";
// 网关名称
@Value("${spring.application.name}")
private String self;
// 网关路由
private final RouteLocator routeLocator;
@Autowired
public SwaggerResourceConfig(RouteLocator routeLocator) {
this.routeLocator = routeLocator;
}
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<SwaggerResource>();
List<String> routeHosts = new ArrayList<>();
routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
.filter(route -> !self.equals(route.getUri().getHost()))
.subscribe(route -> routeHosts.add(route.getUri().getHost()));
Set<String> dealed = new HashSet<>();
// gateway.discovery.locator.enabled 必须为false
// 否则gateway.routes项不生效
routeHosts.forEach(instance -> {
// 通过负载均衡寻找对应主机
// serviceId/v2/api-docs
String url = "/" + instance + Swagger2URL + "?group=" + instance;
if (!dealed.contains(url)) {
dealed.add(url);
resources.add(swaggerResource(url, instance));
}
});
return resources;
}
private SwaggerResource swaggerResource(String url, String name) {
LOG.info("url:{}, instance:{}", url, name);
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setUrl(url);
swaggerResource.setName(name);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}
# SwaggerHandler.java
@RestController
public class SwaggerHandler {
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
@Autowired(required = false)
private UiConfiguration uiConfiguration;
private final SwaggerResourcesProvider swaggerResources;
@Autowired
public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
this.swaggerResources = swaggerResources;
}
@GetMapping("/swagger-resources/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/swagger-resources/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping({"", "/csrf", "/swagger-resources"})
public Mono<ResponseEntity> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}
启动文件,添加注解@EnableEurekaClient
@EnableEurekaClient
@SpringBootApplication
public class DocApplication {
public static void main(String[] args) {
SpringApplication.run(DocApplication.class, args);
}
}
子项目 正常访问
- http://127.0.0.1:9001/system/doc.html
- http://127.0.0.1:9002/business/doc.html
通过网关 访问子项目
- http://127.0.0.1:9003/system/doc.html
- http://127.0.0.1:9003/business/doc.html
聚合访问
- http://127.0.0.1:9003/doc.html