Gateway+Swagger2配置聚合文檔方式
Spring Cloud Gateway網關模塊聚合各微服務的Swagger接口文檔
效果如下圖

相關pom依賴
<!-- 網關路由代理 (僅網關)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!--swagger2 (網關和服務端)-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.7.0.RELEASE</version>
</dependency>Gateway配置
因為Swagger暫不支持webflux項目,所以Gateway里不能配置SwaggerConfig
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/**
* 功能描述: 采用路由id做資源名稱,predicates.Path做映射的方式.
* 如果需要自定義資源名稱,可以單獨配置一個集合(route.id,name),創(chuàng)建swaggerResource時,
* 通過route.id獲取name.
* <p>例如: swagger:
* route_names:
* - name: 訂單
* id: order_route
* - name: 訂單1
* id: order_route1
* spring: cloud: gateway: routes:
* - id: order_route
* - id: order_route1
* </p>
* 重新Gateway的方法還沒研究出來 - -||
*
* @Author:
* @Date: 2021-04-25 15:38
* @Version 1.0
**/
@Component
@Primary
public class Swagger2 implements SwaggerResourcesProvider {
protected static final String API_URI = "/v2/api-docs";//固定后綴
private final RouteLocator routeLocator;
private final GatewayProperties gatewayProperties;
//資源集合
private static List<SwaggerResource> resources;
//自定義資源名稱需要在這里初始化
public Swagger2(RouteLocator routeLocator, GatewayProperties gatewayProperties) {
this.routeLocator = routeLocator;
this.gatewayProperties = gatewayProperties;
}
@Override
public List<SwaggerResource> get() {
//做了一個簡單緩存,沒仔細設計,其實可有可無用處不大
if (resources == null) {
resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
//結合配置的route-路徑(Path),和route過濾,只獲取有效的route節(jié)點
gatewayProperties.getRoutes().stream()
.filter(routeDefinition -> routes.contains(routeDefinition.getId()))
.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
.forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(),
predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
.replace("/**", API_URI)))));
}
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;
import java.util.Optional;
@RestController
@RequestMapping("/swagger-resources")
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("/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("")
public Mono<ResponseEntity> swaggerResources() {
//入口
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}
swagger地址過濾器
使用swagger 的 try it out 功能發(fā)現路徑錯誤,缺少服務器映射前綴的時候在用下面的過濾器.swagger 在拼裝URL 數據時候,會增加X-Forwarder-Prefix 請求頭里面的信息為前綴
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (!StringUtils.endsWithIgnoreCase(path, Swagger2.API_URI)) {
return chain.filter(exchange);
}
String basePath = path.substring(0, path.lastIndexOf(Swagger2.API_URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}
配置文件
spring: cloud: gateway: routes:
#路由的ID,沒有固定規(guī)則但要求唯一,簡易配合服務名
- id: order_route
#匹配后提供服務的路由地址
#uri: http://localhost:8001
#匹配后提供服務的路由地址,lb后跟提供服務的微服務的名,不要寫錯
uri: lb://order
#斷言
predicates:
#路徑相匹配的進行路由
- Path=/order/**
#過濾掉url里的city,例如http://ip:port/city/getCity -> http://ip:port/getCity
#filters:
# - RewritePath=/city/(?<segment>.*), /$\{segment}
filters:
# - SwaggerHeaderFilter
- StripPrefix=1 #不要忘了
服務端
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
/**
* 功能描述: Swagger2 接口文檔
*
* @Author:
* @Date: 2021-04-23 15:59
* @Version 1.0
**/
@Configuration
@EnableSwagger2
public class Swagger2 {
//是否開啟swagger,正式環(huán)境一般是需要關閉的,可根據springboot的多環(huán)境配置進行設置
@Value(value = "${swagger.enabled}")
private Boolean swaggerEnabled;
//顯示文檔版本
@Value(value = "${swagger.version}")
private String version;
//標題
@Value(value = "${swagger.title}")
private String title;
//描述信息
@Value(value = "${swagger.description}")
private String description;
//掃描接口位置 也可以配置到nacos中
private static final String base_package = "com.demo.controller";
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)// 指定api類型為swagger2
.apiInfo(apiInfo())// 用于定義api文檔匯總信息
// 是否開啟
.enable(swaggerEnabled).select()
// 掃描的路徑包
.apis(RequestHandlerSelectors.basePackage(base_package))
// 指定路徑處理PathSelectors.any()代表所有的路徑
.paths(PathSelectors.any()).build()
.pathMapping("/")
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
//securitySchemes的ApiKey中增加一個名為“Authorization”,type為“header”的參數
private List<ApiKey> securitySchemes() {
List<ApiKey> apiKeyList = new ArrayList();
apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
return apiKeyList;
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
return securityReferences;
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!auth).*$"))
.build());
return securityContexts;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(title)// 文檔頁標題
.contact(new Contact("s","s.com","s@163.com"))// 詳細信息
.version(version)// 文檔版本號
.termsOfServiceUrl("www.baidu.com")// 網站地址
.description(description)
.build();
}
}
```java
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Apache?SkyWalking?監(jiān)控?MySQL?Server?實戰(zhàn)解析
這篇文章主要介紹了Apache?SkyWalking?監(jiān)控?MySQL?Server?實戰(zhàn)解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09
springBoot集成redis的key,value序列化的相關問題
這篇文章主要介紹了springBoot集成redis的key,value序列化的相關問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08
java使用randomaccessfile在文件任意位置寫入數據
Java在文件任意位置寫入數據可以使用RandomAccessFile方法來完成,下面看一個簡單的示例就明白了2014-01-01
Java多線程之線程通信生產者消費者模式及等待喚醒機制代碼詳解
這篇文章主要介紹了Java多線程之線程通信生產者消費者模式及等待喚醒機制代碼詳解,具有一定參考價值,需要的朋友可以了解下。2017-10-10

