目錄
- 寫在前邊
- 問題描述
- 解決方案
- 效果
- 我的swagger配置
寫在前邊
當你看到這篇文章時,默認已經整合好了Springcloud/gateway/springfox(swaggerui3), 僅僅是在進行測驗服務時出現問題,
問題描述
通過swagger-ui頁面訪問時會忽略服務名直接訪問swagger映射出的介面,但是我們是通過網關轉發的,這么一訪問就直接404;如下所示:

出現這個問題,就是Servers映射沒有達到我們的要求,我需要的是加上服務名的servers,但是默認卻只有網關的ip和埠,沒有當前的服務名;如下圖所示:

很奇怪,我嘗試通過在swagger配置中添加servers來改變這個Inferred Url,但是一直無效,debug后發現在AbstractDocumentationPluginsBootstrapper類中第96行執行之后就沒有了,導致在請求時沒有servers,然后swagger會創建一個默認的servers,這個默認的就是網關的ip+埠,

現在問題已經找到了,要么修改這個scan方法,要么在請求時構建默認的 Inferred Url 時做手腳,看代碼后發現請求時改這個創建默認的Inferred Url 比較簡便,就修改了這個創建方式;默認的呼叫和創建方式如下:


解決方案
那么這樣就可以創建一個完整包路徑與它一樣的包,自己創建一個名字一樣的類來覆寫框架中的類,然后在創建Inferred Url時添加上服務名,服務名Swagger已經放到請求頭中了,取出來添加上就可以了,
SpecGeneration.java
package springfox.documentation.oas.web;
import io.swagger.v3.oas.models.servers.Server;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import static org.slf4j.LoggerFactory.getLogger;
/**
* 嘗試用該類替換框架中的類
*
* @author vains
* @date 2021/4/6 11:21
*/
@Slf4j
public class SpecGeneration {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private static final Logger LOGGER = getLogger(SpecGeneration.class);
public static final String OPEN_API_SPECIFICATION_PATH
= "${springfox.documentation.open-api.v3.path:/v3/api-docs}";
protected static final String HAL_MEDIA_TYPE = "application/hal+json";
private SpecGeneration() {
throw new UnsupportedOperationException();
}
/**
* 創建一個默認的 swagger 的server
*
* @param requestPrefix /v3/api-docs
* @param requestUrl 請求的url
* @return Server
*/
public static Server inferredServer(String requestPrefix, String requestUrl) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String serverUrl = requestUrl.replace(requestPrefix, "");
String header = null;
try {
URI url = new URI(requestUrl);
serverUrl = String.format("%s://%s:%s", url.getScheme(), url.getHost(), url.getPort());
header = request.getHeader(HEADER_NAME);
if (!StringUtils.isEmpty(header)) {
log.info("當前的服務為:{}", header);
serverUrl += header;
}
} catch (URISyntaxException e) {
LOGGER.error("Unable to parse request url:" + requestUrl);
}
String description = "Inferred Url";
if (!StringUtils.isEmpty(header)) {
description += " For " + header.substring(1);
}
return new Server()
.url(serverUrl)
.description(description);
}
public static String decode(String requestURI) {
try {
return URLDecoder.decode(requestURI, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
return requestURI;
}
}
}
注意,包的路徑一定不能錯!!然后這個類只要保證配置swagger的專案能夠訪問就可以了

效果
然后打開/swagger-ui/頁面,就發現服務名已經添加成功了,

嘗試請求一個介面,路徑也正確,

至此,問題解決,
我的swagger配置
配置參考:springcloud gateway 整合swagger3.0.0
網關中的配置:
SwaggerProvider.java
import com.vains.config.properties.ApplicationNameConfig;
import lombok.AllArgsConstructor;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* swagger3介面檔案配置
*
* @author vains
* @date 2021/4/5 2:42
*/
@Primary
@Configuration
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {
/**
* swagger2默認的url后綴
*/
public static final String SWAGGER2URL = "/v2/api-docs";
/**
* swagger3默認的url后綴
* 要使用ui的話 改成v2 不然會出bug 比如有的地方 沒有輸入框
*/
public static final String SWAGGER3URL = "/v3/api-docs";
/**
* 網關路由
*/
private final RouteLocator routeLocator;
/**
* 網關應用名稱
*/
private ApplicationNameConfig applicationNameConfig;
/**
* 對于gateway來說這塊比較重要 讓swagger能找到對應的服務
*
* @return 服務串列
*/
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routeHosts = new ArrayList<>();
// 獲取所有可用的host:serviceId
routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)
.filter(route -> !applicationNameConfig.getName().equals(route.getUri().getHost()))
.subscribe(route -> routeHosts.add(route.getUri().getHost()));
// 記錄已經添加過的server
Set<String> added = new HashSet<>();
routeHosts.forEach(instance -> {
// 拼接url
String url = "/" + instance.toLowerCase() + SWAGGER3URL;
if (!added.contains(url)) {
added.add(url);
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setUrl(url);
swaggerResource.setName(instance);
resources.add(swaggerResource);
}
});
return resources;
}
}
ApplicationNameConfig.java
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 獲取應用名稱
*
* @author vains
* @date 2021/4/5 2:44
*/
@Data
@Component
@ConfigurationProperties(prefix = ApplicationNameConfig.PREFIX)
public class ApplicationNameConfig {
static final String PREFIX = "spring.application";
/**
* 應用名稱
*/
private String name;
}
其它微服務中的Swagger配置:
SwaggerConfig.java
import com.vains.config.properties.SwaggerProperties;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestHeader;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
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 java.util.Collections;
/**
* swagger3配置
*
* @author vains
* @date 2021/4/5 2:36
*/
@EnableOpenApi
@Configuration
@AllArgsConstructor
public class SwaggerConfig {
private final SwaggerProperties swaggerProperties;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30)
.enable(swaggerProperties.getEnable())
.host(swaggerProperties.getTryHost())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build().apiInfo(
new ApiInfoBuilder()
.title(swaggerProperties.getApplicationName() + " Restful Apis.")
.description(swaggerProperties.getApplicationDescription())
.version(swaggerProperties.getApplicationVersion())
.termsOfServiceUrl(swaggerProperties.getTryHost())
.build())
// 忽略注解
.ignoredParameterTypes(RequestHeader.class)
// Bearer Token 加入 swagger
.securitySchemes(Collections.singletonList(
new ApiKey("Authorization", "Authorization", "header")
))
.securityContexts(Collections.singletonList(
SecurityContext.builder()
.securityReferences(Collections.singletonList(SecurityReference.builder()
.scopes(new AuthorizationScope[0])
.reference("Authorization")
.build()))
.operationSelector(o ->
o.requestMappingPattern().matches("/.*")
)
.build()
)
);
}
}
SwaggerProperties.java
package com.vains.config.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 自定義swagger3屬性
*
* @author vains
* @date 2021/4/5 2:36
*/
@Data
@Component
@ConfigurationProperties(prefix = SwaggerProperties.PREFIX)
public class SwaggerProperties {
static final String PREFIX = "swagger";
/**
* 是否開啟swagger,生產環境一般關閉,所以這里定義一個變數
*/
private Boolean enable;
/**
* 專案應用名
*/
private String applicationName;
/**
* 專案版本資訊
*/
private String applicationVersion;
/**
* 專案描述資訊
*/
private String applicationDescription;
/**
* 介面除錯地址
*/
private String tryHost;
}
如果有什么疑問或更好的解決方案可在評論區留言,謝謝,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/467923.html
標籤:Java
上一篇:Java泛型
下一篇:如何生成一個java檔案
