diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/AbstractSwaggerUiConfigProperties.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/AbstractSwaggerUiConfigProperties.java
index 49e8fe065..b39a6c0cb 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/AbstractSwaggerUiConfigProperties.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/AbstractSwaggerUiConfigProperties.java
@@ -48,7 +48,7 @@
public abstract class AbstractSwaggerUiConfigProperties {
/**
- * The path for the Swagger UI pages to load. Will redirect to the springdoc.webjars.prefix property.
+ * The path for the Swagger UI pages to load.
*/
protected String path = Constants.DEFAULT_SWAGGER_UI_PATH;
@@ -814,4 +814,4 @@ public String toString() {
}
}
-}
\ No newline at end of file
+}
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SpringDocConfigProperties.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SpringDocConfigProperties.java
index 1ea92f1ff..12425bc9d 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SpringDocConfigProperties.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/properties/SpringDocConfigProperties.java
@@ -44,7 +44,6 @@
import org.springframework.context.annotation.Lazy;
import org.springframework.http.MediaType;
-import static org.springdoc.core.utils.Constants.DEFAULT_WEB_JARS_PREFIX_URL;
import static org.springdoc.core.utils.Constants.SPRINGDOC_ENABLED;
/**
@@ -64,11 +63,6 @@ public class SpringDocConfigProperties {
*/
private boolean showActuator;
- /**
- * The Webjars.
- */
- private Webjars webjars = new Webjars();
-
/**
* The Api docs.
*/
@@ -786,24 +780,6 @@ public void setShowActuator(boolean showActuator) {
this.showActuator = showActuator;
}
- /**
- * Gets webjars.
- *
- * @return the webjars
- */
- public Webjars getWebjars() {
- return webjars;
- }
-
- /**
- * Sets webjars.
- *
- * @param webjars the webjars
- */
- public void setWebjars(Webjars webjars) {
- this.webjars = webjars;
- }
-
/**
* Gets api docs.
*
@@ -1390,36 +1366,6 @@ public void setEnabled(boolean enabled) {
}
}
- /**
- * The type Webjars.
- *
- * @author bnasslahsen
- */
- public static class Webjars {
- /**
- * The Prefix.
- */
- private String prefix = DEFAULT_WEB_JARS_PREFIX_URL;
-
- /**
- * Gets prefix.
- *
- * @return the prefix
- */
- public String getPrefix() {
- return prefix;
- }
-
- /**
- * Sets prefix.
- *
- * @param prefix the prefix
- */
- public void setPrefix(String prefix) {
- this.prefix = prefix;
- }
- }
-
/**
* The type Api docs.
*
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java
index 2a2e916f7..9d0bb0db5 100644
--- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java
@@ -26,9 +26,8 @@
package org.springdoc.core.utils;
-import org.springframework.util.ResourceUtils;
-
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
+import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
/**
* The type Constants.
@@ -70,7 +69,7 @@ public final class Constants {
/**
* The constant SWAGGER_CONFIG_URL.
*/
- public static final String SWAGGER_CONFIG_URL = API_DOCS_URL + DEFAULT_PATH_SEPARATOR + SWAGGER_CONFIG_FILE;
+ public static final String SWAGGER_CONFIG_URL = API_DOCS_URL + "/" + SWAGGER_CONFIG_FILE;
/**
* The constant YAML.
@@ -177,21 +176,25 @@ public final class Constants {
*/
public static final String SPRINGDOC_ACTUATOR_DOC_DESCRIPTION = "Spring Boot Actuator Web API Documentation";
- /**
- * The constant DEFAULT_WEB_JARS_PREFIX_URL.
- */
- public static final String DEFAULT_WEB_JARS_PREFIX_URL = "/webjars";
+ /**
+ * The constant CLASSPATH_RESOURCE_LOCATION.
+ */
+ public static final String CLASSPATH_RESOURCE_LOCATION = CLASSPATH_URL_PREFIX + "META-INF" + DEFAULT_PATH_SEPARATOR + "resources" + DEFAULT_PATH_SEPARATOR;
- /**
- * The constant CLASSPATH_RESOURCE_LOCATION.
- */
- public static final String CLASSPATH_RESOURCE_LOCATION = ResourceUtils.CLASSPATH_URL_PREFIX + "/META-INF/resources";
+ /**
+ * The constant WEBJARS_RESOURCE_LOCATION.
+ */
+ public static final String WEBJARS_RESOURCE_LOCATION = CLASSPATH_RESOURCE_LOCATION + "webjars" + DEFAULT_PATH_SEPARATOR;
+ /**
+ * The constant SWAGGER_UI_WEBJAR_NAME.
+ */
+ public static final String SWAGGER_UI_WEBJAR_NAME = "swagger-ui";
/**
* The constant SWAGGER_UI_PREFIX.
*/
- public static final String SWAGGER_UI_PREFIX = "/swagger-ui";
+ public static final String SWAGGER_UI_PREFIX = "/" + SWAGGER_UI_WEBJAR_NAME;
/**
* The constant INDEX_PAGE.
@@ -231,7 +234,7 @@ public final class Constants {
/**
* The constant DEFAULT_SWAGGER_UI_PATH.
*/
- public static final String DEFAULT_SWAGGER_UI_PATH = DEFAULT_PATH_SEPARATOR + "swagger-ui.html";
+ public static final String DEFAULT_SWAGGER_UI_PATH = "/swagger-ui.html";
/**
* The constant SWAGGER_UI_PATH.
@@ -363,6 +366,21 @@ public final class Constants {
*/
public static final String ALL_PATTERN = "/**";
+ /**
+ * The constant SWAGGER_UI_WEBJAR_NAME_PATTERN.
+ */
+ public static final String SWAGGER_UI_WEBJAR_NAME_PATTERN = "/*" + SWAGGER_UI_WEBJAR_NAME;
+
+ /**
+ * The constant SWAGGER_INITIALIZER_PATTERN.
+ */
+ public static final String SWAGGER_INITIALIZER_PATTERN = "/*" + SWAGGER_INITIALIZER_JS;
+
+ /**
+ * The constant SWAGGER_RESOURCE_CACHE_NAME.
+ */
+ public static final String SWAGGER_RESOURCE_CACHE_NAME = "swagger-resource-chain-cache";
+
/**
* The constant HEALTH_PATTERN.
*/
@@ -397,7 +415,7 @@ public final class Constants {
/**
* The constant DEFAULT_YAML_API_DOCS_ACTUATOR_PATH.
*/
- public static final String DEFAULT_YAML_API_DOCS_ACTUATOR_PATH = DEFAULT_PATH_SEPARATOR + YAML;
+ public static final String DEFAULT_YAML_API_DOCS_ACTUATOR_PATH = "/" + YAML;
/**
* The constant ACTUATOR_DEFAULT_GROUP.
diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/ui/AbstractSwaggerConfigurer.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/ui/AbstractSwaggerConfigurer.java
new file mode 100644
index 000000000..583dd2ffb
--- /dev/null
+++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/ui/AbstractSwaggerConfigurer.java
@@ -0,0 +1,196 @@
+package org.springdoc.ui;
+
+import org.springdoc.core.properties.SwaggerUiConfigProperties;
+import org.springframework.boot.autoconfigure.web.WebProperties;
+import org.springframework.web.util.pattern.PathPattern;
+import org.springframework.web.util.pattern.PathPatternParser;
+import org.springframework.web.util.pattern.PatternParseException;
+
+import java.util.Arrays;
+
+import static org.springdoc.core.utils.Constants.ALL_PATTERN;
+import static org.springdoc.core.utils.Constants.SWAGGER_INITIALIZER_PATTERN;
+import static org.springdoc.core.utils.Constants.SWAGGER_UI_PREFIX;
+import static org.springdoc.core.utils.Constants.SWAGGER_UI_WEBJAR_NAME;
+import static org.springdoc.core.utils.Constants.SWAGGER_UI_WEBJAR_NAME_PATTERN;
+import static org.springdoc.core.utils.Constants.WEBJARS_RESOURCE_LOCATION;
+import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
+
+/**
+ * The type Abstract swagger configurer.
+ */
+public abstract class AbstractSwaggerConfigurer {
+
+ /**
+ * The Swagger ui config properties.
+ */
+ private final SwaggerUiConfigProperties swaggerUiConfigProperties;
+
+ /**
+ * The Spring Web config properties.
+ */
+ private final WebProperties springWebProperties;
+
+ /**
+ * The path pattern parser.
+ */
+ private final PathPatternParser parser = new PathPatternParser();
+
+ /**
+ * Instantiates a new Abstract swagger configurer.
+ *
+ * @param swaggerUiConfigProperties the swagger ui calculated config
+ * @param springWebProperties the spring web config
+ */
+ protected AbstractSwaggerConfigurer(SwaggerUiConfigProperties swaggerUiConfigProperties, WebProperties springWebProperties) {
+ this.swaggerUiConfigProperties = swaggerUiConfigProperties;
+ this.springWebProperties = springWebProperties;
+ }
+
+ /**
+ * Gets the handler configs for mapping Swagger UI resources.
+ *
+ * @return the Swagger UI handler configs.
+ */
+ protected SwaggerResourceHandlerConfig[] getSwaggerHandlerConfigs() {
+ String swaggerUiPattern = getUiRootPath() + SWAGGER_UI_PREFIX + ALL_PATTERN;
+ String swaggerUiInitializerPattern = combinePatterns(swaggerUiPattern, SWAGGER_INITIALIZER_PATTERN);
+ String swaggerUiResourceLocation = WEBJARS_RESOURCE_LOCATION + SWAGGER_UI_WEBJAR_NAME + DEFAULT_PATH_SEPARATOR +
+ swaggerUiConfigProperties.getVersion() + DEFAULT_PATH_SEPARATOR;
+
+ return new SwaggerResourceHandlerConfig[]{
+ SwaggerResourceHandlerConfig.createCached()
+ .setPatterns(swaggerUiPattern)
+ .setLocations(swaggerUiResourceLocation),
+ SwaggerResourceHandlerConfig.createUncached()
+ .setPatterns(swaggerUiInitializerPattern)
+ .setLocations(swaggerUiResourceLocation)
+ };
+ }
+
+ /**
+ * Gets the handler configs for mapping webjar resources for the Swagger UI.
+ *
+ * @return the Swagger UI webjar handler configs.
+ */
+ protected SwaggerResourceHandlerConfig[] getSwaggerWebjarHandlerConfigs() {
+ if (!springWebProperties.getResources().isAddMappings()) return new SwaggerResourceHandlerConfig[]{};
+
+ String swaggerUiWebjarPattern = combinePatterns(getWebjarsPathPattern(), SWAGGER_UI_WEBJAR_NAME_PATTERN) + ALL_PATTERN;
+ String swaggerUiWebjarInitializerPattern = combinePatterns(swaggerUiWebjarPattern, SWAGGER_INITIALIZER_PATTERN);
+ String swaggerUiWebjarVersionInitializerPattern = combinePatterns(swaggerUiWebjarPattern,
+ swaggerUiConfigProperties.getVersion() + SWAGGER_INITIALIZER_PATTERN);
+ String swaggerUiWebjarResourceLocation = WEBJARS_RESOURCE_LOCATION;
+
+ return new SwaggerResourceHandlerConfig[]{
+ SwaggerResourceHandlerConfig.createCached()
+ .setPatterns(swaggerUiWebjarPattern)
+ .setLocations(swaggerUiWebjarResourceLocation),
+ SwaggerResourceHandlerConfig.createUncached()
+ .setPatterns(swaggerUiWebjarInitializerPattern, swaggerUiWebjarVersionInitializerPattern)
+ .setLocations(swaggerUiWebjarResourceLocation)
+ };
+ }
+
+ /**
+ * Gets the root path for the Swagger UI.
+ *
+ * @return the Swagger UI root path.
+ */
+ protected abstract String getUiRootPath();
+
+ /**
+ * Gets the path pattern for webjar resources.
+ *
+ * @return the webjars path pattern.
+ */
+ protected abstract String getWebjarsPathPattern();
+
+ /**
+ * Combines pattern strings into a new pattern according to the rules of {@link PathPattern#combine}.
+ *
+ *
For example:
+ *
+ * /webjars/** + /swagger-ui/** => /webjars/swagger-ui/**
+ * /documentation/swagger-ui*/** + /*.js => /documentation/swagger-ui*/*.js
+ *
+ *
+ * @param patterns the patterns to combine.
+ *
+ * @return the combination of the patterns strings.
+ *
+ * @throws IllegalArgumentException if the patterns cannot be combined.
+ *
+ * @see PathPattern#combine
+ */
+ protected String combinePatterns(String... patterns) {
+ return Arrays.stream(patterns)
+ .map(this::parsePattern)
+ .reduce(PathPattern::combine)
+ .map(PathPattern::getPatternString)
+ .orElseThrow(IllegalArgumentException::new);
+ }
+
+ /**
+ * Parses a pattern string as a path pattern.
+ *
+ * @param pattern the pattern string.
+ *
+ * @return the parsed path pattern.
+ *
+ * @throws PatternParseException if the pattern string cannot be parsed.
+ */
+ private PathPattern parsePattern(String pattern) {
+ return parser.parse(parser.initFullPathPattern(pattern));
+ }
+
+ /**
+ * The type Swagger resource handler config.
+ *
+ * @param cacheResources whether to cache resources.
+ * @param patterns the patterns to match.
+ * @param locations the locations to use.
+ */
+ protected record SwaggerResourceHandlerConfig(boolean cacheResources, String[] patterns, String[] locations) {
+
+ private SwaggerResourceHandlerConfig(boolean cacheResources) {
+ this(cacheResources, new String[]{}, new String[]{});
+ }
+
+ /**
+ * Sets the patterns.
+ *
+ * @param patterns the patterns to match.
+ *
+ * @return the updated config.
+ */
+ public SwaggerResourceHandlerConfig setPatterns(String... patterns) {
+ return new SwaggerResourceHandlerConfig(cacheResources, patterns, locations);
+ }
+
+ /**
+ * Sets the locations.
+ *
+ * @param locations the locations to use.
+ *
+ * @return the updated config.
+ */
+ public SwaggerResourceHandlerConfig setLocations(String... locations) {
+ return new SwaggerResourceHandlerConfig(cacheResources, patterns, locations);
+ }
+
+ /**
+ * Create a Swagger resource handler config with resource caching enabled.
+ */
+ public static SwaggerResourceHandlerConfig createCached() {
+ return new SwaggerResourceHandlerConfig(true);
+ }
+
+ /**
+ * Create a Swagger resource handler config with resource caching disabled.
+ */
+ public static SwaggerResourceHandlerConfig createUncached() {
+ return new SwaggerResourceHandlerConfig(false);
+ }
+ }
+}
diff --git a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java
index f9f1eddb2..b8260dd0f 100644
--- a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java
+++ b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java
@@ -33,7 +33,6 @@
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springdoc.core.properties.SwaggerUiOAuthProperties;
-import org.springdoc.core.providers.ActuatorProvider;
import org.springdoc.core.providers.ObjectMapperProvider;
import org.springdoc.core.providers.SpringWebProvider;
import org.springdoc.webflux.core.providers.SpringWebFluxProvider;
@@ -47,6 +46,7 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
import org.springframework.boot.webflux.autoconfigure.WebFluxProperties;
import org.springframework.context.annotation.Bean;
@@ -121,19 +121,21 @@ SwaggerUiHome swaggerUiHome(Optional optionalWebFluxPropertie
* Swagger web flux configurer swagger web flux configurer.
*
* @param swaggerUiConfigProperties the swagger ui calculated config
- * @param springDocConfigProperties the spring doc config properties
+ * @param springWebProperties the spring web config
+ * @param springWebFluxProperties the spring webflux config
* @param swaggerIndexTransformer the swagger index transformer
- * @param actuatorProvider the actuator provider
* @param swaggerResourceResolver the swagger resource resolver
+ * @param swaggerWelcomeCommon the swagger welcome common
* @return the swagger web flux configurer
*/
@Bean
@ConditionalOnMissingBean
@Lazy(false)
SwaggerWebFluxConfigurer swaggerWebFluxConfigurer(SwaggerUiConfigProperties swaggerUiConfigProperties,
- SpringDocConfigProperties springDocConfigProperties, SwaggerIndexTransformer swaggerIndexTransformer,
- Optional actuatorProvider, SwaggerResourceResolver swaggerResourceResolver) {
- return new SwaggerWebFluxConfigurer(swaggerUiConfigProperties, springDocConfigProperties, swaggerIndexTransformer, actuatorProvider, swaggerResourceResolver);
+ WebProperties springWebProperties, WebFluxProperties springWebFluxProperties,
+ SwaggerIndexTransformer swaggerIndexTransformer, SwaggerResourceResolver swaggerResourceResolver,
+ SwaggerWelcomeCommon swaggerWelcomeCommon) {
+ return new SwaggerWebFluxConfigurer(swaggerUiConfigProperties, springWebProperties, springWebFluxProperties, swaggerIndexTransformer, swaggerResourceResolver, swaggerWelcomeCommon);
}
/**
diff --git a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfigResource.java b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfigResource.java
index cf803ddc5..560de709f 100644
--- a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfigResource.java
+++ b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfigResource.java
@@ -30,9 +30,9 @@
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.http.MediaType;
-import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.server.ServerWebExchange;
import static org.springdoc.core.utils.Constants.SWAGGER_CONFIG_URL;
@@ -61,13 +61,13 @@ public SwaggerConfigResource(SwaggerWelcomeCommon swaggerWelcomeCommon) {
/**
* Gets swagger ui config.
*
- * @param request the request
+ * @param exchange the exchange
* @return the swagger ui config
*/
@Operation(hidden = true)
@GetMapping(value = SWAGGER_CONFIG_URL, produces = MediaType.APPLICATION_JSON_VALUE)
- public Map getSwaggerUiConfig(ServerHttpRequest request) {
- return swaggerWelcomeCommon.getSwaggerUiConfig(request);
+ public Map getSwaggerUiConfig(ServerWebExchange exchange) {
+ return swaggerWelcomeCommon.getSwaggerUiConfig(exchange);
}
}
diff --git a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerIndexPageTransformer.java b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerIndexPageTransformer.java
index d68eb838d..190d2432d 100644
--- a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerIndexPageTransformer.java
+++ b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerIndexPageTransformer.java
@@ -71,9 +71,9 @@ public SwaggerIndexPageTransformer(SwaggerUiConfigProperties swaggerUiConfig, Sw
}
@Override
- public Mono transform(ServerWebExchange serverWebExchange, Resource resource, ResourceTransformerChain resourceTransformerChain) {
+ public Mono transform(ServerWebExchange exchange, Resource resource, ResourceTransformerChain resourceTransformerChain) {
SwaggerUiConfigParameters swaggerUiConfigParameters = new SwaggerUiConfigParameters(swaggerUiConfig);
- swaggerWelcomeCommon.buildFromCurrentContextPath(swaggerUiConfigParameters, serverWebExchange.getRequest());
+ swaggerWelcomeCommon.buildFromCurrentContextPath(swaggerUiConfigParameters, exchange);
final AntPathMatcher antPathMatcher = new AntPathMatcher();
try {
diff --git a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWebFluxConfigurer.java b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWebFluxConfigurer.java
index 1be092419..9e8cd6d0c 100644
--- a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWebFluxConfigurer.java
+++ b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWebFluxConfigurer.java
@@ -26,38 +26,35 @@
package org.springdoc.webflux.ui;
-import java.util.Optional;
-
-import org.springdoc.core.properties.SpringDocConfigProperties;
+import org.springdoc.core.properties.SwaggerUiConfigParameters;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
-import org.springdoc.core.providers.ActuatorProvider;
+import org.springdoc.ui.AbstractSwaggerConfigurer;
+import org.springframework.boot.autoconfigure.web.WebProperties;
+import org.springframework.boot.webflux.autoconfigure.WebFluxProperties;
+import org.springframework.cache.Cache;
+import org.springframework.cache.concurrent.ConcurrentMapCache;
+import org.springframework.http.CacheControl;
+import org.springframework.web.reactive.config.ResourceChainRegistration;
+import org.springframework.web.reactive.config.ResourceHandlerRegistration;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
+import org.springframework.web.reactive.resource.CachingResourceResolver;
-import static org.springdoc.core.utils.Constants.ALL_PATTERN;
-import static org.springdoc.core.utils.Constants.CLASSPATH_RESOURCE_LOCATION;
-import static org.springdoc.core.utils.Constants.DEFAULT_WEB_JARS_PREFIX_URL;
-import static org.springdoc.core.utils.Constants.SWAGGER_UI_PREFIX;
-import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
+import static org.springdoc.core.utils.Constants.SWAGGER_RESOURCE_CACHE_NAME;
/**
* The type Swagger web flux configurer.
*
* @author bnasslahsen
*/
-public class SwaggerWebFluxConfigurer implements WebFluxConfigurer {
+public class SwaggerWebFluxConfigurer extends AbstractSwaggerConfigurer implements WebFluxConfigurer {
/**
* The Swagger index transformer.
*/
private final SwaggerIndexTransformer swaggerIndexTransformer;
- /**
- * The Actuator provider.
- */
- private final Optional actuatorProvider;
-
/**
* The Swagger resource resolver.
*/
@@ -69,64 +66,106 @@ public class SwaggerWebFluxConfigurer implements WebFluxConfigurer {
private final SwaggerUiConfigProperties swaggerUiConfigProperties;
/**
- * The Spring doc config properties.
+ * The Spring WebFlux config properties.
+ */
+ private final WebFluxProperties springWebFluxProperties;
+
+ /**
+ * The Swagger welcome common.
+ */
+ private final SwaggerWelcomeCommon swaggerWelcomeCommon;
+
+ /**
+ * The Swagger resource chain cache.
*/
- private final SpringDocConfigProperties springDocConfigProperties;
+ private Cache cache;
/**
* Instantiates a new Swagger web flux configurer.
*
* @param swaggerUiConfigProperties the swagger ui calculated config
- * @param springDocConfigProperties the spring doc config properties
+ * @param springWebProperties the spring web config
+ * @param springWebFluxProperties the spring webflux config
* @param swaggerIndexTransformer the swagger index transformer
- * @param actuatorProvider the actuator provider
* @param swaggerResourceResolver the swagger resource resolver
+ * @param swaggerWelcomeCommon the swagger welcome common
*/
public SwaggerWebFluxConfigurer(SwaggerUiConfigProperties swaggerUiConfigProperties,
- SpringDocConfigProperties springDocConfigProperties,
- SwaggerIndexTransformer swaggerIndexTransformer,
- Optional actuatorProvider, SwaggerResourceResolver swaggerResourceResolver) {
+ WebProperties springWebProperties, WebFluxProperties springWebFluxProperties,
+ SwaggerIndexTransformer swaggerIndexTransformer, SwaggerResourceResolver swaggerResourceResolver,
+ SwaggerWelcomeCommon swaggerWelcomeCommon) {
+ super(swaggerUiConfigProperties, springWebProperties);
this.swaggerIndexTransformer = swaggerIndexTransformer;
- this.actuatorProvider = actuatorProvider;
this.swaggerResourceResolver = swaggerResourceResolver;
this.swaggerUiConfigProperties = swaggerUiConfigProperties;
- this.springDocConfigProperties = springDocConfigProperties;
+ this.springWebFluxProperties = springWebFluxProperties;
+ this.swaggerWelcomeCommon = swaggerWelcomeCommon;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
- StringBuilder uiRootPath = new StringBuilder();
- String swaggerPath = swaggerUiConfigProperties.getPath();
- if (swaggerPath.contains(DEFAULT_PATH_SEPARATOR))
- uiRootPath.append(swaggerPath, 0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
- if (actuatorProvider.isPresent() && actuatorProvider.get().isUseManagementPort())
- uiRootPath.append(actuatorProvider.get().getBasePath());
-
- String webjarsPrefix = springDocConfigProperties.getWebjars().getPrefix();
- String resourcePath, swaggerUiPrefix, swaggerUiWebjarsPrefix;
-
- if (DEFAULT_WEB_JARS_PREFIX_URL.equals(webjarsPrefix)) {
- swaggerUiPrefix = SWAGGER_UI_PREFIX;
- resourcePath = webjarsPrefix + SWAGGER_UI_PREFIX + DEFAULT_PATH_SEPARATOR + swaggerUiConfigProperties.getVersion() + DEFAULT_PATH_SEPARATOR;
- swaggerUiWebjarsPrefix = webjarsPrefix + swaggerUiPrefix;
+ addSwaggerResourceHandlers(registry, getSwaggerHandlerConfigs());
+ addSwaggerResourceHandlers(registry, getSwaggerWebjarHandlerConfigs());
+ }
+
+ /**
+ * Add resource handlers that use the Swagger resource resolver and transformer.
+ *
+ * @param registry the resource handler registry.
+ * @param handlerConfigs the swagger handler configs.
+ */
+ protected void addSwaggerResourceHandlers(ResourceHandlerRegistry registry, SwaggerResourceHandlerConfig... handlerConfigs) {
+ for (SwaggerResourceHandlerConfig handlerConfig : handlerConfigs) {
+ addSwaggerResourceHandler(registry, handlerConfig);
}
- else {
- swaggerUiPrefix = webjarsPrefix;
- resourcePath = DEFAULT_WEB_JARS_PREFIX_URL + DEFAULT_PATH_SEPARATOR;
- swaggerUiWebjarsPrefix = swaggerUiPrefix;
+ }
+
+ /**
+ * Add a resource handler that uses the Swagger resource resolver and transformer.
+ *
+ * @param registry the resource handler registry.
+ * @param handlerConfig the swagger handler config.
+ */
+ protected void addSwaggerResourceHandler(ResourceHandlerRegistry registry, SwaggerResourceHandlerConfig handlerConfig) {
+ ResourceHandlerRegistration handlerRegistration = registry.addResourceHandler(handlerConfig.patterns());
+ handlerRegistration.addResourceLocations(handlerConfig.locations());
+
+ ResourceChainRegistration chainRegistration;
+ if (handlerConfig.cacheResources()) {
+ chainRegistration = handlerRegistration.resourceChain(true, getCache());
+ } else {
+ handlerRegistration.setUseLastModified(false);
+ handlerRegistration.setCacheControl(CacheControl.noStore());
+
+ chainRegistration = handlerRegistration.resourceChain(false);
+ chainRegistration.addResolver(new CachingResourceResolver(getCache())); // only use cache for resolving
}
- registry.addResourceHandler(uiRootPath + swaggerUiWebjarsPrefix + ALL_PATTERN)
- .addResourceLocations(CLASSPATH_RESOURCE_LOCATION + resourcePath)
- .resourceChain(false)
- .addResolver(swaggerResourceResolver)
- .addTransformer(swaggerIndexTransformer);
-
- registry.addResourceHandler(uiRootPath + swaggerUiPrefix + ALL_PATTERN)
- .addResourceLocations(CLASSPATH_RESOURCE_LOCATION + resourcePath)
- .resourceChain(false)
- .addResolver(swaggerResourceResolver)
- .addTransformer(swaggerIndexTransformer);
+ chainRegistration.addResolver(swaggerResourceResolver);
+ chainRegistration.addTransformer(swaggerIndexTransformer);
+ }
+
+ @Override
+ protected String getUiRootPath() {
+ SwaggerUiConfigParameters swaggerUiConfigParameters = new SwaggerUiConfigParameters(swaggerUiConfigProperties);
+ swaggerWelcomeCommon.calculateUiRootPath(swaggerUiConfigParameters);
+
+ return swaggerUiConfigParameters.getUiRootPath();
}
+ @Override
+ protected String getWebjarsPathPattern() {
+ return springWebFluxProperties.getWebjarsPathPattern();
+ }
+
+ /**
+ * Gets the Swagger resource chain cache.
+ *
+ * @return the cache.
+ */
+ protected Cache getCache() {
+ if (cache == null) cache = new ConcurrentMapCache(SWAGGER_RESOURCE_CACHE_NAME);
+
+ return cache;
+ }
}
diff --git a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeActuator.java b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeActuator.java
index e8b2a2c16..7f4b394b2 100644
--- a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeActuator.java
+++ b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeActuator.java
@@ -37,10 +37,9 @@
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpoint;
import org.springframework.http.MediaType;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.server.ServerWebExchange;
import static org.springdoc.core.utils.Constants.DEFAULT_API_DOCS_ACTUATOR_URL;
import static org.springdoc.core.utils.Constants.DEFAULT_SWAGGER_UI_ACTUATOR_PATH;
@@ -82,29 +81,28 @@ public SwaggerWelcomeActuator(SwaggerUiConfigProperties swaggerUiConfig
/**
* Redirect to ui mono.
*
- * @param request the request
- * @param response the response
+ * @param exchange the exchange
* @return the mono
*/
@Operation(hidden = true)
@GetMapping(DEFAULT_PATH_SEPARATOR)
@Override
- public Mono redirectToUi(ServerHttpRequest request, ServerHttpResponse response) {
- return super.redirectToUi(request, response);
+ public Mono redirectToUi(ServerWebExchange exchange) {
+ return super.redirectToUi(exchange);
}
/**
* Openapi yaml map.
*
- * @param request the request
+ * @param exchange the exchange
* @return the map
*/
@Operation(hidden = true)
@GetMapping(value = SWAGGER_CONFIG_ACTUATOR_URL, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@Override
- public Map getSwaggerUiConfig(ServerHttpRequest request) {
- return super.getSwaggerUiConfig(request);
+ public Map getSwaggerUiConfig(ServerWebExchange exchange) {
+ return super.getSwaggerUiConfig(exchange);
}
@Override
diff --git a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeCommon.java b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeCommon.java
index 87660e686..6b810491d 100644
--- a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeCommon.java
+++ b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeCommon.java
@@ -34,16 +34,14 @@
import org.springdoc.core.properties.SwaggerUiConfigParameters;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springdoc.ui.AbstractSwaggerWelcome;
+import org.springframework.http.HttpHeaders;
+import org.springframework.web.util.ForwardedHeaderUtils;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpStatus;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpResponse;
-import org.springframework.web.util.ForwardedHeaderUtils;
+import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
-import static org.springdoc.core.utils.Constants.DEFAULT_WEB_JARS_PREFIX_URL;
-
/**
* The type Swagger welcome common.
*
@@ -65,52 +63,44 @@ protected SwaggerWelcomeCommon(SwaggerUiConfigProperties swaggerUiConfig, Spring
/**
* Redirect to ui mono.
*
- * @param request the request
- * @param response the response
+ * @param exchange the exchange
* @return the mono
*/
- protected Mono redirectToUi(ServerHttpRequest request, ServerHttpResponse response) {
+ protected Mono redirectToUi(ServerWebExchange exchange) {
SwaggerUiConfigParameters swaggerUiConfigParameters = new SwaggerUiConfigParameters(swaggerUiConfig);
- buildFromCurrentContextPath(swaggerUiConfigParameters, request);
- String webjarsPrefix = springDocConfigProperties.getWebjars().getPrefix();
- String additionalPrefix = DEFAULT_WEB_JARS_PREFIX_URL.equals(webjarsPrefix) ? "" : webjarsPrefix;
- String sbUrl = swaggerUiConfigParameters.getContextPath()
- + swaggerUiConfigParameters.getUiRootPath()
- + additionalPrefix
- + getSwaggerUiUrl();
+ buildFromCurrentContextPath(swaggerUiConfigParameters, exchange);
+ String sbUrl = swaggerUiConfigParameters.getContextPath() + swaggerUiConfigParameters.getUiRootPath() + getSwaggerUiUrl();
UriComponentsBuilder uriBuilder = getUriComponentsBuilder(swaggerUiConfigParameters, sbUrl);
+
// forward all queryParams from original request
- request.getQueryParams().forEach(uriBuilder::queryParam);
- response.setStatusCode(HttpStatus.FOUND);
- response.getHeaders().setLocation(URI.create(uriBuilder.build().encode().toString()));
- return response.setComplete();
+ exchange.getRequest().getQueryParams().forEach(uriBuilder::queryParam);
+
+ exchange.getResponse().setStatusCode(HttpStatus.FOUND);
+ exchange.getResponse().getHeaders().setLocation(URI.create(uriBuilder.build().encode().toString()));
+ return exchange.getResponse().setComplete();
}
@Override
protected void calculateOauth2RedirectUrl(SwaggerUiConfigParameters swaggerUiConfigParameters, UriComponentsBuilder uriComponentsBuilder) {
if (StringUtils.isBlank(swaggerUiConfig.getOauth2RedirectUrl()) || !swaggerUiConfigParameters.isValidUrl(swaggerUiConfig.getOauth2RedirectUrl())) {
- String webjarsPrefix = springDocConfigProperties.getWebjars().getPrefix();
- String additionalPath = DEFAULT_WEB_JARS_PREFIX_URL.equals(webjarsPrefix) ? "" : webjarsPrefix;
- swaggerUiConfigParameters.setOauth2RedirectUrl(
- uriComponentsBuilder
- .path(swaggerUiConfigParameters.getUiRootPath())
- .path(additionalPath)
- .path(getOauth2RedirectUrl())
- .build()
- .toString()
- );
+ swaggerUiConfigParameters.setOauth2RedirectUrl(uriComponentsBuilder
+ .path(swaggerUiConfigParameters.getUiRootPath())
+ .path(getOauth2RedirectUrl()).build().toString());
}
}
+ @Override
+ protected abstract void calculateUiRootPath(SwaggerUiConfigParameters swaggerUiConfigParameters, StringBuilder... sbUrls);
+
/**
* Gets swagger ui config.
*
- * @param request the request
+ * @param exchange the exchange
* @return the swagger ui config
*/
- protected Map getSwaggerUiConfig(ServerHttpRequest request) {
+ protected Map getSwaggerUiConfig(ServerWebExchange exchange) {
SwaggerUiConfigParameters swaggerUiConfigParameters = new SwaggerUiConfigParameters(swaggerUiConfig);
- this.buildFromCurrentContextPath(swaggerUiConfigParameters, request);
+ this.buildFromCurrentContextPath(swaggerUiConfigParameters, exchange);
return swaggerUiConfigParameters.getConfigParameters();
}
@@ -118,22 +108,20 @@ protected Map getSwaggerUiConfig(ServerHttpRequest request) {
* From current context path string.
*
* @param swaggerUiConfigParameters the swagger ui config parameters
- * @param request the request
- * @return the string
+ * @param exchange the exchange
*/
- void buildFromCurrentContextPath(SwaggerUiConfigParameters swaggerUiConfigParameters, ServerHttpRequest request) {
+ protected void buildFromCurrentContextPath(SwaggerUiConfigParameters swaggerUiConfigParameters, ServerWebExchange exchange) {
super.init(swaggerUiConfigParameters);
- swaggerUiConfigParameters.setContextPath(request.getPath().contextPath().value());
- String url = ForwardedHeaderUtils.adaptFromForwardedHeaders(request.getURI(), request.getHeaders()).toUriString();
- String target = UriComponentsBuilder.fromPath(request.getPath().contextPath().value()).toUriString();
- int endIndex = url.indexOf(target) + target.length();
- if (endIndex > 0) {
- url = url.substring(0, endIndex);
- }
- else {
- url = url.replace(request.getPath().toString(), "");
- }
- buildConfigUrl(swaggerUiConfigParameters, UriComponentsBuilder.fromUriString(url));
+
+ String contextPath = exchange.getRequest().getPath().contextPath().value();
+ swaggerUiConfigParameters.setContextPath(contextPath);
+
+ URI uri = exchange.getRequest().getURI();
+ HttpHeaders headers = exchange.getRequest().getHeaders();
+
+ UriComponentsBuilder uriComponentsBuilder = ForwardedHeaderUtils.adaptFromForwardedHeaders(uri, headers)
+ .replacePath(contextPath).replaceQuery(null).fragment(null);
+ buildConfigUrl(swaggerUiConfigParameters, uriComponentsBuilder);
}
}
diff --git a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeWebFlux.java b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeWebFlux.java
index 12e630fd9..84ab55436 100644
--- a/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeWebFlux.java
+++ b/springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWelcomeWebFlux.java
@@ -33,10 +33,9 @@
import org.springdoc.core.providers.SpringWebProvider;
import reactor.core.publisher.Mono;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.server.ServerWebExchange;
import static org.springdoc.core.utils.Constants.SWAGGER_CONFIG_FILE;
import static org.springdoc.core.utils.Constants.SWAGGER_UI_PATH;
@@ -71,15 +70,14 @@ public SwaggerWelcomeWebFlux(SwaggerUiConfigProperties swaggerUiConfig, SpringDo
/**
* Redirect to ui mono.
*
- * @param request the request
- * @param response the response
+ * @param exchange the exchange
* @return the mono
*/
@Operation(hidden = true)
@GetMapping(SWAGGER_UI_PATH)
@Override
- public Mono redirectToUi(ServerHttpRequest request, ServerHttpResponse response) {
- return super.redirectToUi(request, response);
+ public Mono redirectToUi(ServerWebExchange exchange) {
+ return super.redirectToUi(exchange);
}
@Override
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app18/SpringDocApp18Test.java b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app18/SpringDocApp18Test.java
index 1a16f01e3..f64e295f3 100644
--- a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app18/SpringDocApp18Test.java
+++ b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app18/SpringDocApp18Test.java
@@ -45,8 +45,7 @@
properties = { "spring.webflux.base-path=/test",
"server.port=9218",
"springdoc.swagger-ui.path=/documentation/swagger-ui.html",
- "springdoc.api-docs.path=/documentation/v3/api-docs",
- "springdoc.webjars.prefix= /webjars-pref" })
+ "springdoc.api-docs.path=/documentation/v3/api-docs" })
class SpringDocApp18Test extends AbstractCommonTest {
@LocalServerPort
@@ -66,7 +65,7 @@ void testIndex() throws Exception {
.exchangeToMono(clientResponse -> Mono.just(clientResponse.statusCode())).block();
assertThat(httpStatusMono).isEqualTo(HttpStatus.FOUND);
- httpStatusMono = webClient.get().uri("/test/documentation/webjars-pref/swagger-ui/index.html")
+ httpStatusMono = webClient.get().uri("/test/documentation/swagger-ui/index.html")
.exchangeToMono(clientResponse -> Mono.just(clientResponse.statusCode())).block();
assertThat(httpStatusMono).isEqualTo(HttpStatus.OK);
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app3/SpringDocApp3RedirectWithPrefixTest.java b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app3/SpringDocApp3RedirectWithPrefixTest.java
index c93d0744d..97cb15582 100644
--- a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app3/SpringDocApp3RedirectWithPrefixTest.java
+++ b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app3/SpringDocApp3RedirectWithPrefixTest.java
@@ -28,8 +28,7 @@
@TestPropertySource(properties = {
"springdoc.swagger-ui.path=/documentation/swagger-ui.html",
- "springdoc.api-docs.path=/documentation/v3/api-docs",
- "springdoc.webjars.prefix= /webjars-pref"
+ "springdoc.api-docs.path=/documentation/v3/api-docs"
})
public class SpringDocApp3RedirectWithPrefixTest extends AbstractSpringDocTest {
@@ -38,8 +37,8 @@ void shouldRedirectWithPrefix() {
WebTestClient.ResponseSpec responseSpec = webTestClient.get().uri("/documentation/swagger-ui.html").exchange()
.expectStatus().isFound();
responseSpec.expectHeader()
- .value("Location", Matchers.is("/documentation/webjars-pref/swagger-ui/index.html"));
- webTestClient.get().uri("/documentation/webjars-pref/swagger-ui/index.html").exchange()
+ .value("Location", Matchers.is("/documentation/swagger-ui/index.html"));
+ webTestClient.get().uri("/documentation/swagger-ui/index.html").exchange()
.expectStatus().isOk();
webTestClient.get().uri("/documentation/v3/api-docs/swagger-config").exchange()
.expectStatus().isOk().expectBody().jsonPath("$.validatorUrl").isEqualTo("");
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app33/SpringDocBehindProxyBasePathTest.java b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app33/SpringDocBehindProxyBasePathTest.java
index 9134b91df..22e9a9055 100644
--- a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app33/SpringDocBehindProxyBasePathTest.java
+++ b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app33/SpringDocBehindProxyBasePathTest.java
@@ -41,8 +41,7 @@
"server.forward-headers-strategy=framework",
"server.port=9318",
"springdoc.swagger-ui.path=/documentation/swagger-ui.html",
- "springdoc.api-docs.path=/documentation/v3/api-docs",
- "springdoc.webjars.prefix= /webjars-pref" })
+ "springdoc.api-docs.path=/documentation/v3/api-docs" })
@Import(SpringDocConfig.class)
public class SpringDocBehindProxyBasePathTest extends AbstractCommonTest {
@@ -69,7 +68,7 @@ void testIndex() throws Exception {
.exchangeToMono(clientResponse -> Mono.just(clientResponse.statusCode())).block();
assertThat(httpStatusMono).isEqualTo(HttpStatus.FOUND);
- httpStatusMono = webClient.get().uri(WEBFLUX_BASE_PATH + "/documentation/webjars-pref/swagger-ui/index.html")
+ httpStatusMono = webClient.get().uri(WEBFLUX_BASE_PATH + "/documentation/swagger-ui/index.html")
.header("X-Forwarded-Prefix", X_FORWARD_PREFIX)
.exchangeToMono(clientResponse -> Mono.just(clientResponse.statusCode())).block();
assertThat(httpStatusMono).isEqualTo(HttpStatus.OK);
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app34/SpringDocApp34Test.java b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app34/SpringDocApp34Test.java
index b478b2eb7..2d8f22a37 100644
--- a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app34/SpringDocApp34Test.java
+++ b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app34/SpringDocApp34Test.java
@@ -33,11 +33,14 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-@TestPropertySource(properties = "springdoc.swagger-ui.disable-swagger-default-url=true")
+@TestPropertySource(properties = {
+ "springdoc.swagger-ui.disable-swagger-default-url=true",
+ "springdoc.swagger-ui.path=/documentation/swagger-ui.html"
+})
public class SpringDocApp34Test extends AbstractSpringDocTest {
@Test
- void transformed_index_with_oauth() throws Exception {
+ void testWebJarResourceTransformed() {
EntityExchangeResult getResult = webTestClient.get().uri("/webjars/swagger-ui/swagger-initializer.js")
.exchange()
.expectStatus().isOk()
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app35/HelloController.java b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app35/HelloController.java
new file mode 100644
index 000000000..ed6c4d9f9
--- /dev/null
+++ b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app35/HelloController.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * *
+ * * *
+ * * * * Copyright 2019-2020 the original author or authors.
+ * * * *
+ * * * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * * * you may not use this file except in compliance with the License.
+ * * * * You may obtain a copy of the License at
+ * * * *
+ * * * * https://www.apache.org/licenses/LICENSE-2.0
+ * * * *
+ * * * * Unless required by applicable law or agreed to in writing, software
+ * * * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * * * See the License for the specific language governing permissions and
+ * * * * limitations under the License.
+ * * *
+ * *
+ *
+ *
+ */
+
+package test.org.springdoc.ui.app35;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Size;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class HelloController {
+
+ @GetMapping(value = "/persons")
+ public void persons(@Valid @RequestParam @Size(min = 4, max = 6) String name) {
+
+ }
+
+}
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app35/SpringDocApp35Test.java b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app35/SpringDocApp35Test.java
new file mode 100644
index 000000000..b37e6a083
--- /dev/null
+++ b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app35/SpringDocApp35Test.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * *
+ * * *
+ * * * * Copyright 2019-2020 the original author or authors.
+ * * * *
+ * * * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * * * you may not use this file except in compliance with the License.
+ * * * * You may obtain a copy of the License at
+ * * * *
+ * * * * https://www.apache.org/licenses/LICENSE-2.0
+ * * * *
+ * * * * Unless required by applicable law or agreed to in writing, software
+ * * * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * * * See the License for the specific language governing permissions and
+ * * * * limitations under the License.
+ * * *
+ * *
+ *
+ *
+ */
+
+package test.org.springdoc.ui.app35;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.http.CacheControl;
+import test.org.springdoc.ui.AbstractSpringDocTest;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.web.reactive.server.EntityExchangeResult;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@TestPropertySource(properties = {
+ "spring.webflux.webjars-path-pattern=/webjars-pref/**",
+ "springdoc.swagger-ui.disable-swagger-default-url=true",
+ "springdoc.swagger-ui.path=/documentation/swagger-ui.html"
+})
+public class SpringDocApp35Test extends AbstractSpringDocTest {
+
+ @Test
+ void testWebJarPrefix() {
+ webTestClient.get().uri("/webjars/swagger-ui/swagger-initializer.js")
+ .exchange()
+ .expectStatus().isNotFound();
+
+ EntityExchangeResult getResult = webTestClient.get().uri("/webjars-pref/swagger-ui/swagger-initializer.js")
+ .exchange()
+ .expectStatus().isOk()
+ .expectHeader().cacheControl(CacheControl.noStore())
+ .expectBody().returnResult();
+
+ var responseContent = new String(getResult.getResponseBody());
+ assertFalse(responseContent.contains("https://petstore.swagger.io/v2/swagger.json"));
+ assertTrue(responseContent.contains("/v3/api-docs"));
+ }
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+
+}
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java
new file mode 100644
index 000000000..1b34722d5
--- /dev/null
+++ b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * *
+ * * *
+ * * * * Copyright 2019-2020 the original author or authors.
+ * * * *
+ * * * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * * * you may not use this file except in compliance with the License.
+ * * * * You may obtain a copy of the License at
+ * * * *
+ * * * * https://www.apache.org/licenses/LICENSE-2.0
+ * * * *
+ * * * * Unless required by applicable law or agreed to in writing, software
+ * * * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * * * See the License for the specific language governing permissions and
+ * * * * limitations under the License.
+ * * *
+ * *
+ *
+ *
+ */
+
+package test.org.springdoc.ui.app36;
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Size;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class HelloController {
+
+ @GetMapping(value = "/persons")
+ public void persons(@Valid @RequestParam @Size(min = 4, max = 6) String name) {
+
+ }
+
+}
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java
new file mode 100644
index 000000000..c80dd9347
--- /dev/null
+++ b/springdoc-openapi-starter-webflux-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java
@@ -0,0 +1,53 @@
+/*
+ *
+ * *
+ * * *
+ * * * * Copyright 2019-2020 the original author or authors.
+ * * * *
+ * * * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * * * you may not use this file except in compliance with the License.
+ * * * * You may obtain a copy of the License at
+ * * * *
+ * * * * https://www.apache.org/licenses/LICENSE-2.0
+ * * * *
+ * * * * Unless required by applicable law or agreed to in writing, software
+ * * * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * * * See the License for the specific language governing permissions and
+ * * * * limitations under the License.
+ * * *
+ * *
+ *
+ *
+ */
+
+package test.org.springdoc.ui.app36;
+
+import org.junit.jupiter.api.Test;
+import test.org.springdoc.ui.AbstractSpringDocTest;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.test.context.TestPropertySource;
+
+@TestPropertySource(properties = {
+ "spring.webflux.webjars-path-pattern=/webjars-pref/**",
+ "spring.web.resources.add-mappings=false",
+ "springdoc.swagger-ui.path=/documentation/swagger-ui.html"
+})
+public class SpringDocApp36Test extends AbstractSpringDocTest {
+
+ @Test
+ void testWebJarMappingDisabled() {
+ webTestClient.get().uri("/webjars/swagger-ui/swagger-initializer.js")
+ .exchange()
+ .expectStatus().isNotFound();
+
+ webTestClient.get().uri("/webjars-pref/swagger-ui/swagger-initializer.js")
+ .exchange()
+ .expectStatus().isNotFound();
+ }
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+
+}
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app18-1.json b/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app18-1.json
index e9cf64c6e..305529a92 100644
--- a/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app18-1.json
+++ b/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app18-1.json
@@ -1,6 +1,6 @@
{
"configUrl": "/test/documentation/v3/api-docs/swagger-config",
- "oauth2RedirectUrl": "http://localhost:9218/test/documentation/webjars-pref/swagger-ui/oauth2-redirect.html",
+ "oauth2RedirectUrl": "http://localhost:9218/test/documentation/swagger-ui/oauth2-redirect.html",
"urls": [
{
"url": "/test/documentation/v3/api-docs/users",
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app32-1.json b/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app32-1.json
index c6f06f1f6..f811db83f 100644
--- a/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app32-1.json
+++ b/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app32-1.json
@@ -1,6 +1,6 @@
{
"configUrl": "/path/prefix/documentation/v3/api-docs/swagger-config",
- "oauth2RedirectUrl": "http://localhost:9318/path/prefix/documentation/webjars-pref/swagger-ui/oauth2-redirect.html",
+ "oauth2RedirectUrl": "http://localhost:9318/path/prefix/documentation/swagger-ui/oauth2-redirect.html",
"url": "/path/prefix/documentation/v3/api-docs",
"validatorUrl": ""
}
diff --git a/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app33.json b/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app33.json
index 9d03a31f8..eef083258 100644
--- a/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app33.json
+++ b/springdoc-openapi-starter-webflux-ui/src/test/resources/results/app33.json
@@ -1,6 +1,6 @@
{
"configUrl": "/path/prefix/test/documentation/v3/api-docs/swagger-config",
- "oauth2RedirectUrl": "http://localhost:9318/path/prefix/test/documentation/webjars-pref/swagger-ui/oauth2-redirect.html",
+ "oauth2RedirectUrl": "http://localhost:9318/path/prefix/test/documentation/swagger-ui/oauth2-redirect.html",
"url": "/path/prefix/test/documentation/v3/api-docs",
"validatorUrl": ""
}
diff --git a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java
index 3a1aac8bd..0182c1f86 100644
--- a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java
+++ b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java
@@ -33,7 +33,6 @@
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springdoc.core.properties.SwaggerUiOAuthProperties;
-import org.springdoc.core.providers.ActuatorProvider;
import org.springdoc.core.providers.ObjectMapperProvider;
import org.springdoc.core.providers.SpringWebProvider;
import org.springdoc.webmvc.core.providers.SpringWebMvcProvider;
@@ -47,7 +46,9 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;
+import org.springframework.boot.webmvc.autoconfigure.WebMvcProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@@ -148,17 +149,21 @@ SwaggerIndexTransformer indexPageTransformer(SwaggerUiConfigProperties swaggerUi
* Swagger web mvc configurer swagger web mvc configurer.
*
* @param swaggerUiConfigProperties the swagger ui calculated config
+ * @param springWebProperties the spring web config
+ * @param springWebMvcProperties the spring mvc config
* @param swaggerIndexTransformer the swagger index transformer
- * @param actuatorProvider the actuator provider
* @param swaggerResourceResolver the swagger resource resolver
+ * @param swaggerWelcomeCommon the swagger welcome common
* @return the swagger web mvc configurer
*/
@Bean
@ConditionalOnMissingBean
@Lazy(false)
SwaggerWebMvcConfigurer swaggerWebMvcConfigurer(SwaggerUiConfigProperties swaggerUiConfigProperties,
- SwaggerIndexTransformer swaggerIndexTransformer, Optional actuatorProvider, SwaggerResourceResolver swaggerResourceResolver) {
- return new SwaggerWebMvcConfigurer(swaggerUiConfigProperties, swaggerIndexTransformer, actuatorProvider, swaggerResourceResolver);
+ WebProperties springWebProperties, WebMvcProperties springWebMvcProperties,
+ SwaggerIndexTransformer swaggerIndexTransformer, SwaggerResourceResolver swaggerResourceResolver,
+ SwaggerWelcomeCommon swaggerWelcomeCommon) {
+ return new SwaggerWebMvcConfigurer(swaggerUiConfigProperties, springWebProperties, springWebMvcProperties, swaggerIndexTransformer, swaggerResourceResolver, swaggerWelcomeCommon);
}
/**
diff --git a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWebMvcConfigurer.java b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWebMvcConfigurer.java
index 981eb4205..4ef8305b8 100644
--- a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWebMvcConfigurer.java
+++ b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWebMvcConfigurer.java
@@ -27,12 +27,17 @@
package org.springdoc.webmvc.ui;
import java.util.List;
-import java.util.Optional;
+import org.springdoc.core.properties.SwaggerUiConfigParameters;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
-import org.springdoc.core.providers.ActuatorProvider;
+import org.springdoc.ui.AbstractSwaggerConfigurer;
+import org.springframework.boot.autoconfigure.web.WebProperties;
+import org.springframework.boot.webmvc.autoconfigure.WebMvcProperties;
+import org.springframework.cache.Cache;
+import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.format.FormatterRegistry;
+import org.springframework.http.CacheControl;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.validation.MessageCodesResolver;
@@ -46,23 +51,22 @@
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
+import org.springframework.web.servlet.config.annotation.ResourceChainRegistration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import org.springframework.web.servlet.resource.CachingResourceResolver;
-import static org.springdoc.core.utils.Constants.CLASSPATH_RESOURCE_LOCATION;
-import static org.springdoc.core.utils.Constants.DEFAULT_WEB_JARS_PREFIX_URL;
-import static org.springdoc.core.utils.Constants.SWAGGER_INITIALIZER_JS;
-import static org.springdoc.core.utils.Constants.SWAGGER_UI_PREFIX;
-import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
+import static org.springdoc.core.utils.Constants.SWAGGER_RESOURCE_CACHE_NAME;
/**
* The type Swagger web mvc configurer.
*
* @author bnasslahsen
*/
-public class SwaggerWebMvcConfigurer implements WebMvcConfigurer {
+public class SwaggerWebMvcConfigurer extends AbstractSwaggerConfigurer implements WebMvcConfigurer {
/**
* The Swagger index transformer.
@@ -70,9 +74,9 @@ public class SwaggerWebMvcConfigurer implements WebMvcConfigurer {
private final SwaggerIndexTransformer swaggerIndexTransformer;
/**
- * The Actuator provider.
+ * The Swagger resource resolver.
*/
- private final Optional actuatorProvider;
+ private final SwaggerResourceResolver swaggerResourceResolver;
/**
* The Swagger ui config properties.
@@ -80,48 +84,107 @@ public class SwaggerWebMvcConfigurer implements WebMvcConfigurer {
private final SwaggerUiConfigProperties swaggerUiConfigProperties;
/**
- * The Swagger resource resolver.
+ * The Spring MVC config properties.
*/
- private final SwaggerResourceResolver swaggerResourceResolver;
+ private final WebMvcProperties springWebMvcProperties;
+
+ /**
+ * The Swagger welcome common.
+ */
+ private final SwaggerWelcomeCommon swaggerWelcomeCommon;
+
+ /**
+ * The Swagger resource chain cache.
+ */
+ private Cache cache;
/**
* Instantiates a new Swagger web mvc configurer.
*
* @param swaggerUiConfigProperties the swagger ui calculated config
+ * @param springWebProperties the spring web config
+ * @param springWebMvcProperties the spring mvc config
* @param swaggerIndexTransformer the swagger index transformer
- * @param actuatorProvider the actuator provider
* @param swaggerResourceResolver the swagger resource resolver
+ * @param swaggerWelcomeCommon the swagger welcome common
*/
public SwaggerWebMvcConfigurer(SwaggerUiConfigProperties swaggerUiConfigProperties,
- SwaggerIndexTransformer swaggerIndexTransformer,
- Optional actuatorProvider, SwaggerResourceResolver swaggerResourceResolver) {
+ WebProperties springWebProperties, WebMvcProperties springWebMvcProperties,
+ SwaggerIndexTransformer swaggerIndexTransformer, SwaggerResourceResolver swaggerResourceResolver,
+ SwaggerWelcomeCommon swaggerWelcomeCommon) {
+ super(swaggerUiConfigProperties, springWebProperties);
this.swaggerIndexTransformer = swaggerIndexTransformer;
- this.actuatorProvider = actuatorProvider;
this.swaggerResourceResolver = swaggerResourceResolver;
this.swaggerUiConfigProperties = swaggerUiConfigProperties;
+ this.springWebMvcProperties = springWebMvcProperties;
+ this.swaggerWelcomeCommon = swaggerWelcomeCommon;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
- StringBuilder uiRootPath = new StringBuilder();
- String swaggerPath = swaggerUiConfigProperties.getPath();
- if (swaggerPath.contains(DEFAULT_PATH_SEPARATOR))
- uiRootPath.append(swaggerPath, 0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
- if (actuatorProvider.isPresent() && actuatorProvider.get().isUseManagementPort())
- uiRootPath.append(actuatorProvider.get().getBasePath());
-
- registry.addResourceHandler(uiRootPath + SWAGGER_UI_PREFIX + "*/*" + SWAGGER_INITIALIZER_JS)
- .addResourceLocations(CLASSPATH_RESOURCE_LOCATION + DEFAULT_WEB_JARS_PREFIX_URL + DEFAULT_PATH_SEPARATOR)
- .setCachePeriod(0)
- .resourceChain(false)
- .addResolver(swaggerResourceResolver)
- .addTransformer(swaggerIndexTransformer);
-
- registry.addResourceHandler(uiRootPath + SWAGGER_UI_PREFIX + "*/**")
- .addResourceLocations(CLASSPATH_RESOURCE_LOCATION + DEFAULT_WEB_JARS_PREFIX_URL + DEFAULT_PATH_SEPARATOR)
- .resourceChain(false)
- .addResolver(swaggerResourceResolver)
- .addTransformer(swaggerIndexTransformer);
+ addSwaggerResourceHandlers(registry, getSwaggerHandlerConfigs());
+ addSwaggerResourceHandlers(registry, getSwaggerWebjarHandlerConfigs());
+ }
+
+ /**
+ * Add resource handlers that use the Swagger resource resolver and transformer.
+ *
+ * @param registry the resource handler registry.
+ * @param handlerConfigs the swagger handler configs.
+ */
+ protected void addSwaggerResourceHandlers(ResourceHandlerRegistry registry, SwaggerResourceHandlerConfig... handlerConfigs) {
+ for (SwaggerResourceHandlerConfig handlerConfig : handlerConfigs) {
+ addSwaggerResourceHandler(registry, handlerConfig);
+ }
+ }
+
+ /**
+ * Add a resource handler that uses the Swagger resource resolver and transformer.
+ *
+ * @param registry the resource handler registry.
+ * @param handlerConfig the swagger handler config.
+ */
+ protected void addSwaggerResourceHandler(ResourceHandlerRegistry registry, SwaggerResourceHandlerConfig handlerConfig) {
+ ResourceHandlerRegistration handlerRegistration = registry.addResourceHandler(handlerConfig.patterns());
+ handlerRegistration.addResourceLocations(handlerConfig.locations());
+
+ ResourceChainRegistration chainRegistration;
+ if (handlerConfig.cacheResources()) {
+ chainRegistration = handlerRegistration.resourceChain(true, getCache());
+ } else {
+ handlerRegistration.setUseLastModified(false);
+ handlerRegistration.setCacheControl(CacheControl.noStore());
+
+ chainRegistration = handlerRegistration.resourceChain(false);
+ chainRegistration.addResolver(new CachingResourceResolver(getCache())); // only use cache for resolving
+ }
+
+ chainRegistration.addResolver(swaggerResourceResolver);
+ chainRegistration.addTransformer(swaggerIndexTransformer);
+ }
+
+ @Override
+ protected String getUiRootPath() {
+ SwaggerUiConfigParameters swaggerUiConfigParameters = new SwaggerUiConfigParameters(swaggerUiConfigProperties);
+ swaggerWelcomeCommon.calculateUiRootPath(swaggerUiConfigParameters);
+
+ return swaggerUiConfigParameters.getUiRootPath();
+ }
+
+ @Override
+ protected String getWebjarsPathPattern() {
+ return springWebMvcProperties.getWebjarsPathPattern();
+ }
+
+ /**
+ * Gets the Swagger resource chain cache.
+ *
+ * @return the cache.
+ */
+ protected Cache getCache() {
+ if (cache == null) cache = new ConcurrentMapCache(SWAGGER_RESOURCE_CACHE_NAME);
+
+ return cache;
}
@Override
diff --git a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeCommon.java b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeCommon.java
index 7fa79368a..b82245567 100644
--- a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeCommon.java
+++ b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeCommon.java
@@ -26,6 +26,8 @@
package org.springdoc.webmvc.ui;
+import java.net.URI;
+import java.util.Collections;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
@@ -35,9 +37,11 @@
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springdoc.ui.AbstractSwaggerWelcome;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+import org.springframework.web.util.ForwardedHeaderUtils;
+import org.springframework.web.util.ServletRequestPathUtils;
import org.springframework.web.util.UriComponentsBuilder;
/**
@@ -46,6 +50,7 @@
* @author bnasslashen
*/
public abstract class SwaggerWelcomeCommon extends AbstractSwaggerWelcome {
+
/**
* Instantiates a new Abstract swagger welcome.
*
@@ -96,16 +101,31 @@ protected void calculateOauth2RedirectUrl(SwaggerUiConfigParameters swaggerUiCon
.path(getOauth2RedirectUrl()).build().toString());
}
+ @Override
+ protected abstract void calculateUiRootPath(SwaggerUiConfigParameters swaggerUiConfigParameters, StringBuilder... sbUrls);
+
/**
* From current context path.
*
* @param swaggerUiConfigParameters the swagger ui config parameters
* @param request the request
*/
- void buildFromCurrentContextPath(SwaggerUiConfigParameters swaggerUiConfigParameters, HttpServletRequest request) {
+ protected void buildFromCurrentContextPath(SwaggerUiConfigParameters swaggerUiConfigParameters, HttpServletRequest request) {
super.init(swaggerUiConfigParameters);
- swaggerUiConfigParameters.setContextPath(request.getContextPath());
- buildConfigUrl(swaggerUiConfigParameters, ServletUriComponentsBuilder.fromCurrentContextPath());
+
+ String servletPath = ServletRequestPathUtils.getServletPathPrefix(request);
+ String contextPath = request.getContextPath() + (servletPath != null ? servletPath : "");
+ swaggerUiConfigParameters.setContextPath(contextPath);
+
+ URI uri = URI.create(request.getRequestURL().toString());
+ HttpHeaders headers = new HttpHeaders();
+ for (String name : Collections.list(request.getHeaderNames())) {
+ headers.addAll(name, Collections.list(request.getHeaders(name)));
+ }
+
+ UriComponentsBuilder uriComponentsBuilder = ForwardedHeaderUtils.adaptFromForwardedHeaders(uri, headers)
+ .replacePath(contextPath).replaceQuery(null).fragment(null);
+ buildConfigUrl(swaggerUiConfigParameters, uriComponentsBuilder);
}
}
diff --git a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeWebMvc.java b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeWebMvc.java
index a6be3f41e..236762f05 100644
--- a/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeWebMvc.java
+++ b/springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerWelcomeWebMvc.java
@@ -32,7 +32,6 @@
import org.springdoc.core.properties.SwaggerUiConfigParameters;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springdoc.core.providers.SpringWebProvider;
-import org.springdoc.core.utils.SpringDocUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
@@ -86,18 +85,9 @@ public ResponseEntity redirectToUi(HttpServletRequest request) {
@Override
protected void calculateUiRootPath(SwaggerUiConfigParameters swaggerUiConfigParameters, StringBuilder... sbUrls) {
StringBuilder sbUrl = new StringBuilder();
- if (SpringDocUtils.isValidPath(mvcServletPath))
- sbUrl.append(mvcServletPath);
calculateUiRootCommon(swaggerUiConfigParameters, sbUrl, sbUrls);
}
- @Override
- protected String buildUrl(String contextPath, final String docsUrl) {
- if (SpringDocUtils.isValidPath(mvcServletPath))
- contextPath += mvcServletPath;
- return super.buildUrl(contextPath, docsUrl);
- }
-
@Override
protected void buildApiDocUrl(SwaggerUiConfigParameters swaggerUiConfigParameters) {
swaggerUiConfigParameters.setApiDocsUrl(buildUrlWithContextPath(swaggerUiConfigParameters, springDocConfigProperties.getApiDocs().getPath()));
@@ -107,7 +97,12 @@ protected void buildApiDocUrl(SwaggerUiConfigParameters swaggerUiConfigParameter
protected String buildUrlWithContextPath(SwaggerUiConfigParameters swaggerUiConfigParameters, String swaggerUiUrl) {
if (swaggerUiConfigParameters.getPathPrefix() == null)
swaggerUiConfigParameters.setPathPrefix(springWebProvider.findPathPrefix(springDocConfigProperties));
- return buildUrl(swaggerUiConfigParameters.getContextPath() + swaggerUiConfigParameters.getPathPrefix(), swaggerUiUrl);
+ if (swaggerUiUrl.startsWith(swaggerUiConfigParameters.getPathPrefix())) {
+ return buildUrl(swaggerUiConfigParameters.getContextPath(), swaggerUiUrl);
+ }
+ else {
+ return buildUrl(swaggerUiConfigParameters.getContextPath() + swaggerUiConfigParameters.getPathPrefix(), swaggerUiUrl);
+ }
}
@Override
diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java
new file mode 100644
index 000000000..5129f7062
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/HelloController.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * * Copyright 2019-2020 the original author or authors.
+ * *
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * https://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ *
+ */
+
+package test.org.springdoc.ui.app36;
+
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Size;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class HelloController {
+
+ @GetMapping(value = "/persons")
+ public void persons(@Valid @RequestParam @Size(min = 4, max = 6) String name) {
+
+ }
+
+}
diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java
new file mode 100644
index 000000000..7902fe474
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app36/SpringDocApp36Test.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * * Copyright 2019-2020 the original author or authors.
+ * *
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * https://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ *
+ */
+
+package test.org.springdoc.ui.app36;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.test.context.TestPropertySource;
+import test.org.springdoc.ui.AbstractSpringDocTest;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@TestPropertySource(properties = {
+ "springdoc.swagger-ui.disable-swagger-default-url=true",
+ "springdoc.swagger-ui.path=/documentation/swagger-ui.html"
+})
+public class SpringDocApp36Test extends AbstractSpringDocTest {
+
+ @Test
+ void testWebJarResourceTransformed() throws Exception {
+ mockMvc.perform(get("/webjars/swagger-ui/swagger-initializer.js"))
+ .andExpect(status().isOk())
+ .andExpect(content().string(not(containsString("https://petstore.swagger.io/v2/swagger.json"))))
+ .andExpect(content().string(containsString("/v3/api-docs")));
+ }
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+
+}
diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app37/HelloController.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app37/HelloController.java
new file mode 100644
index 000000000..62daa6a88
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app37/HelloController.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * * Copyright 2019-2020 the original author or authors.
+ * *
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * https://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ *
+ */
+
+package test.org.springdoc.ui.app37;
+
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Size;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class HelloController {
+
+ @GetMapping(value = "/persons")
+ public void persons(@Valid @RequestParam @Size(min = 4, max = 6) String name) {
+
+ }
+
+}
diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app37/SpringDocApp37Test.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app37/SpringDocApp37Test.java
new file mode 100644
index 000000000..e3859e58e
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app37/SpringDocApp37Test.java
@@ -0,0 +1,53 @@
+/*
+ *
+ * * Copyright 2019-2020 the original author or authors.
+ * *
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * https://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ *
+ */
+
+package test.org.springdoc.ui.app37;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.test.context.TestPropertySource;
+import test.org.springdoc.ui.AbstractSpringDocTest;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@TestPropertySource(properties = {
+ "spring.mvc.webjars-path-pattern=/webjars-pref/**",
+ "springdoc.swagger-ui.disable-swagger-default-url=true",
+ "springdoc.swagger-ui.path=/documentation/swagger-ui.html"
+})
+public class SpringDocApp37Test extends AbstractSpringDocTest {
+
+ @Test
+ void testWebJarPrefix() throws Exception {
+ mockMvc.perform(get("/webjars/swagger-ui/swagger-initializer.js"))
+ .andExpect(status().isNotFound());
+
+ mockMvc.perform(get("/webjars-pref/swagger-ui/swagger-initializer.js"))
+ .andExpect(status().isOk())
+ .andExpect(content().string(not(containsString("https://petstore.swagger.io/v2/swagger.json"))))
+ .andExpect(content().string(containsString("/v3/api-docs")));
+ }
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+
+}
diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app38/HelloController.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app38/HelloController.java
new file mode 100644
index 000000000..603b7928e
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app38/HelloController.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * * Copyright 2019-2020 the original author or authors.
+ * *
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * https://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ *
+ */
+
+package test.org.springdoc.ui.app38;
+
+
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Size;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class HelloController {
+
+ @GetMapping(value = "/persons")
+ public void persons(@Valid @RequestParam @Size(min = 4, max = 6) String name) {
+
+ }
+
+}
diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app38/SpringDocApp38Test.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app38/SpringDocApp38Test.java
new file mode 100644
index 000000000..aee3b80fd
--- /dev/null
+++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app38/SpringDocApp38Test.java
@@ -0,0 +1,48 @@
+/*
+ *
+ * * Copyright 2019-2020 the original author or authors.
+ * *
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * * you may not use this file except in compliance with the License.
+ * * You may obtain a copy of the License at
+ * *
+ * * https://www.apache.org/licenses/LICENSE-2.0
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the License is distributed on an "AS IS" BASIS,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the License for the specific language governing permissions and
+ * * limitations under the License.
+ *
+ */
+
+package test.org.springdoc.ui.app38;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.test.context.TestPropertySource;
+import test.org.springdoc.ui.AbstractSpringDocTest;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@TestPropertySource(properties = {
+ "spring.mvc.webjars-path-pattern=/webjars-pref/**",
+ "spring.web.resources.add-mappings=false",
+ "springdoc.swagger-ui.path=/documentation/swagger-ui.html"
+})
+public class SpringDocApp38Test extends AbstractSpringDocTest {
+
+ @Test
+ void testWebJarMappingDisabled() throws Exception {
+ mockMvc.perform(get("/webjars/swagger-ui/swagger-initializer.js"))
+ .andExpect(status().isNotFound());
+
+ mockMvc.perform(get("/webjars-pref/swagger-ui/swagger-initializer.js"))
+ .andExpect(status().isNotFound());
+ }
+
+ @SpringBootApplication
+ static class SpringDocTestApp {}
+
+}
diff --git a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app8/SpringDocApp8MultipleUrlsSeveralParallelRequestsTest.java b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app8/SpringDocApp8MultipleUrlsSeveralParallelRequestsTest.java
index 77919360c..91142151f 100644
--- a/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app8/SpringDocApp8MultipleUrlsSeveralParallelRequestsTest.java
+++ b/springdoc-openapi-starter-webmvc-ui/src/test/java/test/org/springdoc/ui/app8/SpringDocApp8MultipleUrlsSeveralParallelRequestsTest.java
@@ -63,7 +63,7 @@ void swagger_config_for_multiple_groups_and_many_parallel_requests() {
assertDoesNotThrow(() -> {
allOf(Stream.generate(() -> runAsync(() -> {
try {
- mockMvc.perform(get("/v3/api-docs/swagger-config"))
+ mockMvc.perform(get("/servlet-path/v3/api-docs/swagger-config").servletPath("/servlet-path"))
.andExpect(status().isOk())
.andExpect(jsonPath("configUrl", equalTo("/servlet-path/v3/api-docs/swagger-config")))
.andExpect(jsonPath("url").doesNotExist())