Skip to content

Commit 6414fbe

Browse files
author
bnasslahsen
committed
ÃAdd support to handle prefix for webflux-ui. fixes #454
1 parent c69671c commit 6414fbe

File tree

16 files changed

+494
-35
lines changed

16 files changed

+494
-35
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/ui/AbstractSwaggerWelcome.java

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public abstract class AbstractSwaggerWelcome implements InitializingBean {
4747
private String originConfigUrl;
4848

4949
@Value(SPRINGDOC_OAUTH2_REDIRECT_URL_VALUE)
50-
private String oauth2RedirectUrl;
50+
protected String oauth2RedirectUrl;
5151

5252
@Value(SPRINGDOC_SWAGGER_UI_URL_VALUE)
5353
private String swaggerUiUrl;
@@ -62,25 +62,14 @@ public void afterPropertiesSet() {
6262
calculateUiRootPath();
6363
}
6464

65-
66-
protected void calculateUiRootPath(StringBuilder... sbUrls) {
67-
StringBuilder sbUrl = new StringBuilder();
68-
if (ArrayUtils.isNotEmpty(sbUrls))
69-
sbUrl = sbUrls[0];
70-
String swaggerPath = swaggerUiConfig.getPath();
71-
if (swaggerPath.contains(DEFAULT_PATH_SEPARATOR))
72-
sbUrl.append(swaggerPath, 0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
73-
this.uiRootPath = sbUrl.toString();
74-
}
75-
7665
protected String buildUrl(String contextPath, final String docsUrl) {
7766
if (contextPath.endsWith(DEFAULT_PATH_SEPARATOR)) {
7867
return contextPath.substring(0, contextPath.length() - 1) + docsUrl;
7968
}
8069
return contextPath + docsUrl;
8170
}
8271

83-
void buildConfigUrl(String contextPath, UriComponentsBuilder uriComponentsBuilder) {
72+
protected void buildConfigUrl(String contextPath, UriComponentsBuilder uriComponentsBuilder) {
8473
String apiDocsUrl = springDocConfigProperties.getApiDocs().getPath();
8574
if (StringUtils.isEmpty(originConfigUrl)) {
8675
String url = buildUrl(contextPath, apiDocsUrl);
@@ -95,12 +84,11 @@ void buildConfigUrl(String contextPath, UriComponentsBuilder uriComponentsBuilde
9584
else
9685
SwaggerUiConfigProperties.addUrl(url);
9786
}
98-
if (StringUtils.isEmpty(oauth2RedirectUrl)) {
99-
swaggerUiConfig.setOauth2RedirectUrl(uriComponentsBuilder.path(this.uiRootPath).path(SWAGGER_UI_OAUTH_REDIRECT_URL).build().toString());
100-
}
101-
else if (!swaggerUiConfig.isValidUrl(swaggerUiConfig.getOauth2RedirectUrl())) {
102-
swaggerUiConfig.setOauth2RedirectUrl(uriComponentsBuilder.path(this.uiRootPath).path(swaggerUiConfig.getOauth2RedirectUrl()).build().toString());
103-
}
87+
calculateOauth2RedirectUrl(uriComponentsBuilder);
10488
}
10589

90+
abstract void calculateOauth2RedirectUrl(UriComponentsBuilder uriComponentsBuilder);
91+
92+
abstract void calculateUiRootPath(StringBuilder... sbUrls);
93+
10694
}

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@
3434
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
3535

3636
import static org.springdoc.core.Constants.CLASSPATH_RESOURCE_LOCATION;
37+
import static org.springdoc.core.Constants.DEFAULT_WEB_JARS_PREFIX_URL;
3738
import static org.springdoc.core.Constants.SPRINGDOC_SWAGGER_UI_ENABLED;
3839
import static org.springdoc.core.Constants.SWAGGER_UI_PATH;
39-
import static org.springdoc.core.Constants.WEB_JARS_PREFIX_URL;
4040
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
4141

4242

@@ -49,9 +49,6 @@ public class SwaggerConfig extends WebMvcConfigurerAdapter { // NOSONAR
4949
@Value(SWAGGER_UI_PATH)
5050
private String swaggerPath;
5151

52-
@Value(WEB_JARS_PREFIX_URL)
53-
private String webJarsPrefixUrl;
54-
5552
@Autowired
5653
private SwaggerIndexTransformer swaggerIndexTransformer;
5754

@@ -62,8 +59,8 @@ public void addResourceHandlers(ResourceHandlerRegistry registry) {
6259
uiRootPath.append(swaggerPath, 0, swaggerPath.lastIndexOf('/'));
6360
}
6461
uiRootPath.append("/**");
65-
String webJarsLocation = webJarsPrefixUrl + DEFAULT_PATH_SEPARATOR;
66-
registry.addResourceHandler(uiRootPath + "/swagger-ui/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATION + webJarsLocation)
62+
registry.addResourceHandler(uiRootPath + "/swagger-ui/**")
63+
.addResourceLocations(CLASSPATH_RESOURCE_LOCATION + DEFAULT_WEB_JARS_PREFIX_URL+DEFAULT_PATH_SEPARATOR)
6764
.resourceChain(false)
6865
.addTransformer(swaggerIndexTransformer);
6966
}

springdoc-openapi-ui/src/main/java/org/springdoc/ui/SwaggerWelcome.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import javax.servlet.http.HttpServletRequest;
2424

2525
import io.swagger.v3.oas.annotations.Operation;
26+
import org.apache.commons.lang3.ArrayUtils;
2627
import org.apache.commons.lang3.StringUtils;
2728
import org.springdoc.core.SpringDocConfigProperties;
2829
import org.springdoc.core.SpringDocConfiguration;
@@ -41,8 +42,10 @@
4142
import static org.springdoc.core.Constants.MVC_SERVLET_PATH;
4243
import static org.springdoc.core.Constants.SPRINGDOC_SWAGGER_UI_ENABLED;
4344
import static org.springdoc.core.Constants.SWAGGER_CONFIG_URL;
45+
import static org.springdoc.core.Constants.SWAGGER_UI_OAUTH_REDIRECT_URL;
4446
import static org.springdoc.core.Constants.SWAGGER_UI_PATH;
4547
import static org.springdoc.core.Constants.SWAGGER_UI_URL;
48+
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
4649
import static org.springframework.web.servlet.view.UrlBasedViewResolver.REDIRECT_URL_PREFIX;
4750

4851
@Controller
@@ -75,17 +78,32 @@ public Map<String, Object> openapiYaml(HttpServletRequest request) {
7578
}
7679

7780
@Override
78-
protected void calculateUiRootPath(StringBuilder... sbUrls) {
81+
void calculateUiRootPath(StringBuilder... sbUrls) {
7982
StringBuilder sbUrl = new StringBuilder();
8083
if (StringUtils.isNotBlank(mvcServletPath))
8184
sbUrl.append(mvcServletPath);
82-
super.calculateUiRootPath(sbUrl);
85+
if (ArrayUtils.isNotEmpty(sbUrls))
86+
sbUrl = sbUrls[0];
87+
String swaggerPath = swaggerUiConfig.getPath();
88+
if (swaggerPath.contains(DEFAULT_PATH_SEPARATOR))
89+
sbUrl.append(swaggerPath, 0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
90+
this.uiRootPath = sbUrl.toString();
8391
}
8492

8593
@Override
8694
protected String buildUrl(String contextPath, final String docsUrl) {
8795
if (StringUtils.isNotBlank(mvcServletPath))
8896
contextPath += mvcServletPath;
89-
return super.buildUrl(contextPath,docsUrl);
97+
return super.buildUrl(contextPath, docsUrl);
98+
}
99+
100+
@Override
101+
void calculateOauth2RedirectUrl(UriComponentsBuilder uriComponentsBuilder) {
102+
if (StringUtils.isEmpty(oauth2RedirectUrl)) {
103+
swaggerUiConfig.setOauth2RedirectUrl(uriComponentsBuilder.path(this.uiRootPath).path(SWAGGER_UI_OAUTH_REDIRECT_URL).build().toString());
104+
}
105+
else if (!swaggerUiConfig.isValidUrl(swaggerUiConfig.getOauth2RedirectUrl())) {
106+
swaggerUiConfig.setOauth2RedirectUrl(uriComponentsBuilder.path(this.uiRootPath).path(swaggerUiConfig.getOauth2RedirectUrl()).build().toString());
107+
}
90108
}
91109
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package test.org.springdoc.ui.app1;
20+
21+
import org.hamcrest.Matchers;
22+
import org.junit.jupiter.api.Test;
23+
import test.org.springdoc.ui.AbstractSpringDocTest;
24+
25+
import org.springframework.boot.autoconfigure.SpringBootApplication;
26+
import org.springframework.test.context.TestPropertySource;
27+
28+
import static org.hamcrest.CoreMatchers.equalTo;
29+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
30+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
31+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
32+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
33+
34+
@TestPropertySource(properties = {
35+
"springdoc.swagger-ui.path=/documentation/swagger-ui.html",
36+
"springdoc.api-docs.path=/documentation/v3/api-docs",
37+
"springdoc.webjars.prefix= /webjars-pref"
38+
})
39+
public class SpringDocAppRedirectWithPrefixTest extends AbstractSpringDocTest {
40+
41+
@Test
42+
public void shouldRedirectWithPrefix() throws Exception {
43+
44+
mockMvc.perform(get("/documentation/v3/api-docs/swagger-config"))
45+
.andExpect(status().isOk())
46+
.andExpect(jsonPath("validatorUrl", equalTo("")))
47+
.andExpect(jsonPath("oauth2RedirectUrl", equalTo("http://localhost/documentation/swagger-ui/oauth2-redirect.html")));
48+
}
49+
50+
@SpringBootApplication
51+
static class SpringDocTestApp {}
52+
53+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package org.springdoc.ui;
20+
21+
import org.springframework.beans.factory.annotation.Value;
22+
import org.springframework.context.annotation.Configuration;
23+
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
24+
import org.springframework.web.reactive.config.WebFluxConfigurer;
25+
26+
import static org.springdoc.core.Constants.CLASSPATH_RESOURCE_LOCATION;
27+
import static org.springdoc.core.Constants.DEFAULT_WEB_JARS_PREFIX_URL;
28+
import static org.springdoc.core.Constants.SWAGGER_UI_PATH;
29+
import static org.springdoc.core.Constants.WEB_JARS_PREFIX_URL;
30+
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
31+
32+
33+
@Configuration
34+
public class SwaggerConfig implements WebFluxConfigurer {
35+
36+
@Value(SWAGGER_UI_PATH)
37+
private String swaggerPath;
38+
39+
@Value(WEB_JARS_PREFIX_URL)
40+
private String webJarsPrefixUrl;
41+
42+
43+
@Override
44+
public void addResourceHandlers(ResourceHandlerRegistry registry) {
45+
StringBuilder uiRootPath = new StringBuilder();
46+
if (swaggerPath.contains("/")) {
47+
uiRootPath.append(swaggerPath, 0, swaggerPath.lastIndexOf('/'));
48+
}
49+
registry.addResourceHandler(uiRootPath + webJarsPrefixUrl+"/**")
50+
.addResourceLocations(CLASSPATH_RESOURCE_LOCATION + DEFAULT_WEB_JARS_PREFIX_URL+DEFAULT_PATH_SEPARATOR)
51+
.resourceChain(false);
52+
}
53+
54+
}

springdoc-openapi-webflux-ui/src/main/java/org/springdoc/ui/SwaggerWelcome.java

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@
2222
import java.util.Map;
2323

2424
import io.swagger.v3.oas.annotations.Operation;
25+
import org.apache.commons.lang3.ArrayUtils;
26+
import org.apache.commons.lang3.StringUtils;
2527
import org.springdoc.core.SpringDocConfigProperties;
2628
import org.springdoc.core.SpringDocConfiguration;
2729
import org.springdoc.core.SwaggerUiConfigProperties;
2830
import reactor.core.publisher.Mono;
2931

32+
import org.springframework.beans.factory.annotation.Value;
3033
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3134
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3235
import org.springframework.http.HttpStatus;
@@ -40,13 +43,19 @@
4043

4144
import static org.springdoc.core.Constants.SPRINGDOC_SWAGGER_UI_ENABLED;
4245
import static org.springdoc.core.Constants.SWAGGER_CONFIG_URL;
46+
import static org.springdoc.core.Constants.SWAGGER_UI_OAUTH_REDIRECT_URL;
4347
import static org.springdoc.core.Constants.SWAGGER_UI_PATH;
4448
import static org.springdoc.core.Constants.SWAGGER_UI_URL;
49+
import static org.springdoc.core.Constants.WEB_JARS_PREFIX_URL;
50+
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
4551

4652
@Controller
4753
@ConditionalOnProperty(name = SPRINGDOC_SWAGGER_UI_ENABLED, matchIfMissing = true)
4854
@ConditionalOnBean(SpringDocConfiguration.class)
49-
public class SwaggerWelcome extends AbstractSwaggerWelcome {
55+
public class SwaggerWelcome extends AbstractSwaggerWelcome {
56+
57+
@Value(WEB_JARS_PREFIX_URL)
58+
private String webJarsPrefixUrl;
5059

5160
public SwaggerWelcome(SwaggerUiConfigProperties swaggerUiConfig, SpringDocConfigProperties springDocConfigProperties) {
5261
super(swaggerUiConfig, springDocConfigProperties);
@@ -55,9 +64,8 @@ public SwaggerWelcome(SwaggerUiConfigProperties swaggerUiConfig, SpringDocConfig
5564
@Operation(hidden = true)
5665
@GetMapping(SWAGGER_UI_PATH)
5766
public Mono<Void> redirectToUi(ServerHttpRequest request, ServerHttpResponse response) {
58-
String contextPath = request.getPath().contextPath().value();
59-
buildConfigUrl(contextPath, UriComponentsBuilder.fromHttpRequest(request));
60-
String sbUrl = this.buildUrl(contextPath,this.uiRootPath + springDocConfigProperties.getWebjars().getPrefix()+ SWAGGER_UI_URL);
67+
String contextPath = this.fromCurrentContextPath(request);
68+
String sbUrl = this.buildUrl(contextPath, this.uiRootPath + springDocConfigProperties.getWebjars().getPrefix() + SWAGGER_UI_URL);
6169
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(sbUrl);
6270
uriBuilder.queryParam(SwaggerUiConfigProperties.CONFIG_URL_PROPERTY, swaggerUiConfig.getConfigUrl());
6371
response.setStatusCode(HttpStatus.TEMPORARY_REDIRECT);
@@ -69,9 +77,36 @@ public Mono<Void> redirectToUi(ServerHttpRequest request, ServerHttpResponse res
6977
@GetMapping(value = SWAGGER_CONFIG_URL, produces = MediaType.APPLICATION_JSON_VALUE)
7078
@ResponseBody
7179
public Map<String, Object> getSwaggerUiConfig(ServerHttpRequest request) {
72-
String contextPath = request.getPath().contextPath().value();
73-
buildConfigUrl(contextPath, UriComponentsBuilder.fromHttpRequest(request));
80+
this.fromCurrentContextPath(request);
7481
return swaggerUiConfig.getConfigParameters();
7582
}
7683

84+
@Override
85+
void calculateUiRootPath(StringBuilder... sbUrls) {
86+
StringBuilder sbUrl = new StringBuilder();
87+
if (ArrayUtils.isNotEmpty(sbUrls))
88+
sbUrl = sbUrls[0];
89+
String swaggerPath = swaggerUiConfig.getPath();
90+
if (swaggerPath.contains(DEFAULT_PATH_SEPARATOR))
91+
sbUrl.append(swaggerPath, 0, swaggerPath.lastIndexOf(DEFAULT_PATH_SEPARATOR));
92+
this.uiRootPath = sbUrl.toString();
93+
}
94+
95+
@Override
96+
void calculateOauth2RedirectUrl(UriComponentsBuilder uriComponentsBuilder) {
97+
if (StringUtils.isEmpty(oauth2RedirectUrl)) {
98+
swaggerUiConfig.setOauth2RedirectUrl(uriComponentsBuilder.path(this.uiRootPath).path(webJarsPrefixUrl + SWAGGER_UI_OAUTH_REDIRECT_URL).build().toString());
99+
}
100+
else if (!swaggerUiConfig.isValidUrl(swaggerUiConfig.getOauth2RedirectUrl())) {
101+
swaggerUiConfig.setOauth2RedirectUrl(uriComponentsBuilder.path(this.uiRootPath).path(swaggerUiConfig.getOauth2RedirectUrl()).build().toString());
102+
}
103+
}
104+
105+
private String fromCurrentContextPath(ServerHttpRequest request) {
106+
String contextPath = request.getPath().contextPath().value();
107+
String url = UriComponentsBuilder.fromHttpRequest(request).toUriString();
108+
url = url.replace(request.getPath().toString(), "");
109+
buildConfigUrl(contextPath, UriComponentsBuilder.fromUriString(url));
110+
return contextPath;
111+
}
77112
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
22
org.springdoc.ui.SwaggerWelcome,\
3+
org.springdoc.ui.SwaggerConfig,\
34
org.springdoc.core.SwaggerUiConfigProperties

springdoc-openapi-webflux-ui/src/test/java/test/org/springdoc/ui/AbstractSpringDocTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springdoc.core.SpringDocConfiguration;
2323
import org.springdoc.core.SpringDocWebFluxConfiguration;
2424
import org.springdoc.core.SwaggerUiConfigProperties;
25+
import org.springdoc.ui.SwaggerConfig;
2526
import org.springdoc.ui.SwaggerWelcome;
2627

2728
import org.springframework.beans.factory.annotation.Autowired;
@@ -33,7 +34,7 @@
3334

3435
@ActiveProfiles("test")
3536
@WebFluxTest
36-
@ContextConfiguration(classes = { SpringDocConfiguration.class, SpringDocConfigProperties.class, SpringDocWebFluxConfiguration.class, SwaggerUiConfigProperties.class, SwaggerWelcome.class })
37+
@ContextConfiguration(classes = { SpringDocConfiguration.class, SpringDocConfigProperties.class, SpringDocWebFluxConfiguration.class, SwaggerUiConfigProperties.class, SwaggerConfig.class, SwaggerWelcome.class })
3738
public abstract class AbstractSpringDocTest {
3839

3940

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
*
3+
* * Copyright 2019-2020 the original author or authors.
4+
* *
5+
* * Licensed under the Apache License, Version 2.0 (the "License");
6+
* * you may not use this file except in compliance with the License.
7+
* * You may obtain a copy of the License at
8+
* *
9+
* * https://www.apache.org/licenses/LICENSE-2.0
10+
* *
11+
* * Unless required by applicable law or agreed to in writing, software
12+
* * distributed under the License is distributed on an "AS IS" BASIS,
13+
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* * See the License for the specific language governing permissions and
15+
* * limitations under the License.
16+
*
17+
*/
18+
19+
package test.org.springdoc.ui.app3;
20+
21+
import javax.validation.Valid;
22+
import javax.validation.constraints.Size;
23+
24+
import org.springframework.web.bind.annotation.GetMapping;
25+
import org.springframework.web.bind.annotation.RequestParam;
26+
import org.springframework.web.bind.annotation.RestController;
27+
28+
@RestController
29+
public class HelloController {
30+
31+
@GetMapping(value = "/persons")
32+
public void persons(@Valid @RequestParam @Size(min = 4, max = 6) String name) {
33+
34+
}
35+
36+
}

0 commit comments

Comments
 (0)