Skip to content

Commit 2551a6f

Browse files
committed
Modify resource handlers to correctly use WebJar path pattern
1 parent 5cf6ab5 commit 2551a6f

File tree

5 files changed

+235
-65
lines changed

5 files changed

+235
-65
lines changed

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/utils/Constants.java

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626

2727
package org.springdoc.core.utils;
2828

29-
import org.springframework.util.ResourceUtils;
30-
3129
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
30+
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
3231

3332
/**
3433
* The type Constants.
@@ -70,7 +69,7 @@ public final class Constants {
7069
/**
7170
* The constant SWAGGER_CONFIG_URL.
7271
*/
73-
public static final String SWAGGER_CONFIG_URL = API_DOCS_URL + DEFAULT_PATH_SEPARATOR + SWAGGER_CONFIG_FILE;
72+
public static final String SWAGGER_CONFIG_URL = API_DOCS_URL + "/" + SWAGGER_CONFIG_FILE;
7473

7574
/**
7675
* The constant YAML.
@@ -177,21 +176,25 @@ public final class Constants {
177176
*/
178177
public static final String SPRINGDOC_ACTUATOR_DOC_DESCRIPTION = "Spring Boot Actuator Web API Documentation";
179178

180-
/**
181-
* The constant DEFAULT_WEB_JARS_PREFIX_URL.
182-
*/
183-
public static final String DEFAULT_WEB_JARS_PREFIX_URL = "/webjars";
179+
/**
180+
* The constant CLASSPATH_RESOURCE_LOCATION.
181+
*/
182+
public static final String CLASSPATH_RESOURCE_LOCATION = CLASSPATH_URL_PREFIX + "META-INF" + DEFAULT_PATH_SEPARATOR + "resources" + DEFAULT_PATH_SEPARATOR;
184183

185-
/**
186-
* The constant CLASSPATH_RESOURCE_LOCATION.
187-
*/
188-
public static final String CLASSPATH_RESOURCE_LOCATION = ResourceUtils.CLASSPATH_URL_PREFIX + "/META-INF/resources";
184+
/**
185+
* The constant WEBJARS_RESOURCE_LOCATION.
186+
*/
187+
public static final String WEBJARS_RESOURCE_LOCATION = CLASSPATH_RESOURCE_LOCATION + "webjars" + DEFAULT_PATH_SEPARATOR;
189188

189+
/**
190+
* The constant SWAGGER_UI_WEBJAR_NAME.
191+
*/
192+
public static final String SWAGGER_UI_WEBJAR_NAME = "swagger-ui";
190193

191194
/**
192195
* The constant SWAGGER_UI_PREFIX.
193196
*/
194-
public static final String SWAGGER_UI_PREFIX = "/swagger-ui";
197+
public static final String SWAGGER_UI_PREFIX = "/" + SWAGGER_UI_WEBJAR_NAME;
195198

196199
/**
197200
* The constant INDEX_PAGE.
@@ -231,7 +234,7 @@ public final class Constants {
231234
/**
232235
* The constant DEFAULT_SWAGGER_UI_PATH.
233236
*/
234-
public static final String DEFAULT_SWAGGER_UI_PATH = DEFAULT_PATH_SEPARATOR + "swagger-ui.html";
237+
public static final String DEFAULT_SWAGGER_UI_PATH = "/swagger-ui.html";
235238

236239
/**
237240
* The constant SWAGGER_UI_PATH.
@@ -363,6 +366,16 @@ public final class Constants {
363366
*/
364367
public static final String ALL_PATTERN = "/**";
365368

369+
/**
370+
* The constant SWAGGER_UI_WEBJAR_NAME_PATTERN.
371+
*/
372+
public static final String SWAGGER_UI_WEBJAR_NAME_PATTERN = "/*" + SWAGGER_UI_WEBJAR_NAME;
373+
374+
/**
375+
* The constant SWAGGER_INITIALIZER_PATTERN.
376+
*/
377+
public static final String SWAGGER_INITIALIZER_PATTERN = "/*" + SWAGGER_INITIALIZER_JS;
378+
366379
/**
367380
* The constant HEALTH_PATTERN.
368381
*/
@@ -397,7 +410,7 @@ public final class Constants {
397410
/**
398411
* The constant DEFAULT_YAML_API_DOCS_ACTUATOR_PATH.
399412
*/
400-
public static final String DEFAULT_YAML_API_DOCS_ACTUATOR_PATH = DEFAULT_PATH_SEPARATOR + YAML;
413+
public static final String DEFAULT_YAML_API_DOCS_ACTUATOR_PATH = "/" + YAML;
401414

402415
/**
403416
* The constant ACTUATOR_DEFAULT_GROUP.

springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerConfig.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
4848
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
4949
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
50+
import org.springframework.boot.autoconfigure.web.WebProperties;
5051
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
5152
import org.springframework.boot.webflux.autoconfigure.WebFluxProperties;
5253
import org.springframework.context.annotation.Bean;
@@ -121,7 +122,8 @@ SwaggerUiHome swaggerUiHome(Optional<WebFluxProperties> optionalWebFluxPropertie
121122
* Swagger web flux configurer swagger web flux configurer.
122123
*
123124
* @param swaggerUiConfigProperties the swagger ui calculated config
124-
* @param springDocConfigProperties the spring doc config properties
125+
* @param springWebProperties the spring web config
126+
* @param springWebFluxProperties the spring webflux config
125127
* @param swaggerIndexTransformer the swagger index transformer
126128
* @param actuatorProvider the actuator provider
127129
* @param swaggerResourceResolver the swagger resource resolver
@@ -131,9 +133,10 @@ SwaggerUiHome swaggerUiHome(Optional<WebFluxProperties> optionalWebFluxPropertie
131133
@ConditionalOnMissingBean
132134
@Lazy(false)
133135
SwaggerWebFluxConfigurer swaggerWebFluxConfigurer(SwaggerUiConfigProperties swaggerUiConfigProperties,
134-
SpringDocConfigProperties springDocConfigProperties, SwaggerIndexTransformer swaggerIndexTransformer,
135-
Optional<ActuatorProvider> actuatorProvider, SwaggerResourceResolver swaggerResourceResolver) {
136-
return new SwaggerWebFluxConfigurer(swaggerUiConfigProperties, springDocConfigProperties, swaggerIndexTransformer, actuatorProvider, swaggerResourceResolver);
136+
WebProperties springWebProperties, WebFluxProperties springWebFluxProperties,
137+
SwaggerIndexTransformer swaggerIndexTransformer, Optional<ActuatorProvider> actuatorProvider,
138+
SwaggerResourceResolver swaggerResourceResolver) {
139+
return new SwaggerWebFluxConfigurer(swaggerUiConfigProperties, springWebProperties, springWebFluxProperties, swaggerIndexTransformer, actuatorProvider, swaggerResourceResolver);
137140
}
138141

139142
/**

springdoc-openapi-starter-webflux-ui/src/main/java/org/springdoc/webflux/ui/SwaggerWebFluxConfigurer.java

Lines changed: 93 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,21 @@
2727
package org.springdoc.webflux.ui;
2828

2929
import java.util.Optional;
30-
31-
import org.springdoc.core.properties.SpringDocConfigProperties;
3230
import org.springdoc.core.properties.SwaggerUiConfigProperties;
3331
import org.springdoc.core.providers.ActuatorProvider;
34-
32+
import org.springframework.boot.autoconfigure.web.WebProperties;
33+
import org.springframework.boot.webflux.autoconfigure.WebFluxProperties;
3534
import org.springframework.http.CacheControl;
3635
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
3736
import org.springframework.web.reactive.config.WebFluxConfigurer;
38-
39-
import static org.springdoc.core.utils.Constants.CLASSPATH_RESOURCE_LOCATION;
40-
import static org.springdoc.core.utils.Constants.DEFAULT_WEB_JARS_PREFIX_URL;
41-
import static org.springdoc.core.utils.Constants.SWAGGER_INITIALIZER_JS;
37+
import org.springframework.web.util.pattern.PathPattern;
38+
import org.springframework.web.util.pattern.PathPatternParser;
39+
import static org.springdoc.core.utils.Constants.ALL_PATTERN;
40+
import static org.springdoc.core.utils.Constants.SWAGGER_INITIALIZER_PATTERN;
4241
import static org.springdoc.core.utils.Constants.SWAGGER_UI_PREFIX;
42+
import static org.springdoc.core.utils.Constants.SWAGGER_UI_WEBJAR_NAME;
43+
import static org.springdoc.core.utils.Constants.SWAGGER_UI_WEBJAR_NAME_PATTERN;
44+
import static org.springdoc.core.utils.Constants.WEBJARS_RESOURCE_LOCATION;
4345
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
4446

4547
/**
@@ -70,51 +72,117 @@ public class SwaggerWebFluxConfigurer implements WebFluxConfigurer {
7072
private final SwaggerUiConfigProperties swaggerUiConfigProperties;
7173

7274
/**
73-
* The Spring doc config properties.
75+
* The Spring Web config properties.
7476
*/
75-
private final SpringDocConfigProperties springDocConfigProperties;
77+
private final WebProperties springWebProperties;
78+
79+
/**
80+
* The Spring WebFlux config properties.
81+
*/
82+
private final WebFluxProperties springWebFluxProperties;
83+
84+
private final PathPatternParser parser = new PathPatternParser();
7685

7786
/**
7887
* Instantiates a new Swagger web flux configurer.
7988
*
8089
* @param swaggerUiConfigProperties the swagger ui calculated config
81-
* @param springDocConfigProperties the spring doc config properties
90+
* @param springWebProperties the spring web config
91+
* @param springWebFluxProperties the spring webflux config
8292
* @param swaggerIndexTransformer the swagger index transformer
8393
* @param actuatorProvider the actuator provider
8494
* @param swaggerResourceResolver the swagger resource resolver
8595
*/
8696
public SwaggerWebFluxConfigurer(SwaggerUiConfigProperties swaggerUiConfigProperties,
87-
SpringDocConfigProperties springDocConfigProperties,
88-
SwaggerIndexTransformer swaggerIndexTransformer,
89-
Optional<ActuatorProvider> actuatorProvider, SwaggerResourceResolver swaggerResourceResolver) {
97+
WebProperties springWebProperties, WebFluxProperties springWebFluxProperties,
98+
SwaggerIndexTransformer swaggerIndexTransformer, Optional<ActuatorProvider> actuatorProvider,
99+
SwaggerResourceResolver swaggerResourceResolver) {
90100
this.swaggerIndexTransformer = swaggerIndexTransformer;
91101
this.actuatorProvider = actuatorProvider;
92102
this.swaggerResourceResolver = swaggerResourceResolver;
93103
this.swaggerUiConfigProperties = swaggerUiConfigProperties;
94-
this.springDocConfigProperties = springDocConfigProperties;
104+
this.springWebProperties = springWebProperties;
105+
this.springWebFluxProperties = springWebFluxProperties;
95106
}
96107

97108
@Override
98109
public void addResourceHandlers(ResourceHandlerRegistry registry) {
99-
StringBuilder uiRootPath = new StringBuilder();
100-
String swaggerPath = swaggerUiConfigProperties.getPath();
101-
if (swaggerPath.contains(DEFAULT_PATH_SEPARATOR))
102-
uiRootPath.append(swaggerPath, 0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
103-
if (actuatorProvider.isPresent() && actuatorProvider.get().isUseManagementPort())
104-
uiRootPath.append(actuatorProvider.get().getBasePath());
110+
String swaggerUiPattern = getUiRootPath() + SWAGGER_UI_PREFIX + ALL_PATTERN;
111+
String swaggerUiResourceLocation = WEBJARS_RESOURCE_LOCATION + SWAGGER_UI_WEBJAR_NAME + DEFAULT_PATH_SEPARATOR +
112+
swaggerUiConfigProperties.getVersion() + DEFAULT_PATH_SEPARATOR;
105113

106-
registry.addResourceHandler(uiRootPath + SWAGGER_UI_PREFIX + "*/*" + SWAGGER_INITIALIZER_JS)
107-
.addResourceLocations(CLASSPATH_RESOURCE_LOCATION + DEFAULT_WEB_JARS_PREFIX_URL + DEFAULT_PATH_SEPARATOR)
108-
.setCacheControl(CacheControl.noStore())
114+
addSwaggerUiResourceHandler(registry, swaggerUiPattern, swaggerUiResourceLocation);
115+
116+
// Add custom mappings for Swagger UI WebJar resources if Spring resource mapping is enabled
117+
if (springWebProperties.getResources().isAddMappings()) {
118+
String webjarsPathPattern = springWebFluxProperties.getWebjarsPathPattern();
119+
120+
String swaggerUiWebjarPattern = mergePatterns(webjarsPathPattern, SWAGGER_UI_WEBJAR_NAME_PATTERN) + ALL_PATTERN;
121+
String swaggerUiWebjarResourceLocation = WEBJARS_RESOURCE_LOCATION;
122+
123+
addSwaggerUiResourceHandler(registry, swaggerUiWebjarPattern, swaggerUiWebjarResourceLocation);
124+
}
125+
}
126+
127+
/**
128+
* Adds the resource handlers for serving the Swagger UI resources.
129+
*/
130+
protected void addSwaggerUiResourceHandler(ResourceHandlerRegistry registry, String pattern, String... resourceLocations) {
131+
registry.addResourceHandler(pattern)
132+
.addResourceLocations(resourceLocations)
109133
.resourceChain(false)
110134
.addResolver(swaggerResourceResolver)
111135
.addTransformer(swaggerIndexTransformer);
112136

113-
registry.addResourceHandler(uiRootPath + SWAGGER_UI_PREFIX + "*/**")
114-
.addResourceLocations(CLASSPATH_RESOURCE_LOCATION + DEFAULT_WEB_JARS_PREFIX_URL + DEFAULT_PATH_SEPARATOR)
137+
// Ensure Swagger initializer has "no-store" Cache-Control header
138+
registry.addResourceHandler(mergePatterns(pattern, SWAGGER_INITIALIZER_PATTERN))
139+
.setCacheControl(CacheControl.noStore())
140+
.addResourceLocations(resourceLocations)
115141
.resourceChain(false)
116142
.addResolver(swaggerResourceResolver)
117143
.addTransformer(swaggerIndexTransformer);
118144
}
119145

146+
/**
147+
* Computes and returns the root path for the Swagger UI.
148+
*
149+
* @return the Swagger UI root path.
150+
*/
151+
protected String getUiRootPath() {
152+
StringBuilder uiRootPath = new StringBuilder();
153+
154+
if (actuatorProvider.isPresent() && actuatorProvider.get().isUseManagementPort()) {
155+
uiRootPath.append(actuatorProvider.get().getBasePath());
156+
}
157+
158+
String swaggerUiPath = swaggerUiConfigProperties.getPath();
159+
if (swaggerUiPath.contains(DEFAULT_PATH_SEPARATOR)) {
160+
uiRootPath.append(swaggerUiPath, 0, swaggerUiPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
161+
}
162+
163+
return uiRootPath.toString();
164+
}
165+
166+
/**
167+
* Combines two patterns into a new pattern according to the rules of {@link PathPattern#combine}.
168+
*
169+
* <p>For example:
170+
* <ul>
171+
* <li><code>/webjars/&#42;&#42;</code> + <code>/swagger-ui/&#42;&#42;</code> => <code>/webjars/swagger-ui/&#42;&#42;</code></li>
172+
* <li><code>/documentation/swagger-ui&#42;/&#42;&#42;</code> + <code>/&#42;.js</code> => <code>/documentation/swagger-ui&#42;/&#42;.js</code></li>
173+
* </ul>
174+
*
175+
* @param pattern1 the first pattern
176+
* @param pattern2 the second pattern
177+
*
178+
* @return the combination of the two patterns
179+
*
180+
* @see PathPattern#combine
181+
*/
182+
private String mergePatterns(String pattern1, String pattern2) {
183+
PathPattern pathPattern1 = parser.parse(parser.initFullPathPattern(pattern1));
184+
PathPattern pathPattern2 = parser.parse(parser.initFullPathPattern(pattern2));
185+
186+
return pathPattern1.combine(pathPattern2).getPatternString();
187+
}
120188
}

springdoc-openapi-starter-webmvc-ui/src/main/java/org/springdoc/webmvc/ui/SwaggerConfig.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@
4747
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
4848
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
4949
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
50+
import org.springframework.boot.autoconfigure.web.WebProperties;
5051
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;
52+
import org.springframework.boot.webmvc.autoconfigure.WebMvcProperties;
5153
import org.springframework.context.annotation.Bean;
5254
import org.springframework.context.annotation.Configuration;
5355
import org.springframework.context.annotation.Lazy;
@@ -148,6 +150,8 @@ SwaggerIndexTransformer indexPageTransformer(SwaggerUiConfigProperties swaggerUi
148150
* Swagger web mvc configurer swagger web mvc configurer.
149151
*
150152
* @param swaggerUiConfigProperties the swagger ui calculated config
153+
* @param springWebProperties the spring web config
154+
* @param springWebMvcProperties the spring mvc config
151155
* @param swaggerIndexTransformer the swagger index transformer
152156
* @param actuatorProvider the actuator provider
153157
* @param swaggerResourceResolver the swagger resource resolver
@@ -157,8 +161,10 @@ SwaggerIndexTransformer indexPageTransformer(SwaggerUiConfigProperties swaggerUi
157161
@ConditionalOnMissingBean
158162
@Lazy(false)
159163
SwaggerWebMvcConfigurer swaggerWebMvcConfigurer(SwaggerUiConfigProperties swaggerUiConfigProperties,
160-
SwaggerIndexTransformer swaggerIndexTransformer, Optional<ActuatorProvider> actuatorProvider, SwaggerResourceResolver swaggerResourceResolver) {
161-
return new SwaggerWebMvcConfigurer(swaggerUiConfigProperties, swaggerIndexTransformer, actuatorProvider, swaggerResourceResolver);
164+
WebProperties springWebProperties, WebMvcProperties springWebMvcProperties,
165+
SwaggerIndexTransformer swaggerIndexTransformer, Optional<ActuatorProvider> actuatorProvider,
166+
SwaggerResourceResolver swaggerResourceResolver) {
167+
return new SwaggerWebMvcConfigurer(swaggerUiConfigProperties, springWebProperties, springWebMvcProperties, swaggerIndexTransformer, actuatorProvider, swaggerResourceResolver);
162168
}
163169

164170
/**

0 commit comments

Comments
 (0)