Skip to content

Commit cbe83f8

Browse files
committed
Make base path configurable for WebFlux applications
This commit adds the `"spring.webflux.base-path"` configuration property. Configuring this property will gather all `HttpHandlers` into a single composite and prefix all requests with a shared base path. Closes gh-10129
1 parent a03a8eb commit cbe83f8

File tree

4 files changed

+117
-5
lines changed

4 files changed

+117
-5
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfiguration.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.boot.autoconfigure.web.reactive;
1818

19+
import java.util.Collections;
20+
import java.util.Map;
21+
1922
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2023
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
2124
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -26,7 +29,9 @@
2629
import org.springframework.context.annotation.Bean;
2730
import org.springframework.context.annotation.Configuration;
2831
import org.springframework.core.Ordered;
32+
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
2933
import org.springframework.http.server.reactive.HttpHandler;
34+
import org.springframework.util.StringUtils;
3035
import org.springframework.web.reactive.DispatcherHandler;
3136
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
3237

@@ -55,8 +60,13 @@ public AnnotationConfig(ApplicationContext applicationContext) {
5560
}
5661

5762
@Bean
58-
public HttpHandler httpHandler() {
59-
return WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
63+
public HttpHandler httpHandler(WebFluxProperties properties) {
64+
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
65+
if (StringUtils.hasText(properties.getBasePath())) {
66+
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
67+
return new ContextPathCompositeHandler(handlersMap);
68+
}
69+
return httpHandler;
6070
}
6171

6272
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxProperties.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.boot.autoconfigure.web.reactive;
1818

1919
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
import org.springframework.util.StringUtils;
2021

2122
/**
2223
* {@link ConfigurationProperties properties} for Spring WebFlux.
@@ -27,6 +28,11 @@
2728
@ConfigurationProperties(prefix = "spring.webflux")
2829
public class WebFluxProperties {
2930

31+
/**
32+
* Base path for all web handlers.
33+
*/
34+
private String basePath;
35+
3036
/**
3137
* Date format to use. For instance, `dd/MM/yyyy`.
3238
*/
@@ -37,6 +43,27 @@ public class WebFluxProperties {
3743
*/
3844
private String staticPathPattern = "/**";
3945

46+
public String getBasePath() {
47+
return basePath;
48+
}
49+
50+
public void setBasePath(String basePath) {
51+
this.basePath = cleanBasePath(basePath);
52+
}
53+
54+
private String cleanBasePath(String basePath) {
55+
String candidate = StringUtils.trimWhitespace(basePath);
56+
if (StringUtils.hasText(candidate)) {
57+
if (!candidate.startsWith("/")) {
58+
candidate = "/" + candidate;
59+
}
60+
if (candidate.endsWith("/")) {
61+
candidate = candidate.substring(0, candidate.length() - 1);
62+
}
63+
}
64+
return candidate;
65+
}
66+
4067
public String getDateFormat() {
4168
return this.dateFormat;
4269
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfigurationTests.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,12 +16,14 @@
1616

1717
package org.springframework.boot.autoconfigure.web.reactive;
1818

19+
import org.assertj.core.api.InstanceOfAssertFactories;
1920
import org.junit.jupiter.api.Test;
2021

2122
import org.springframework.boot.autoconfigure.AutoConfigurations;
2223
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
2324
import org.springframework.context.annotation.Bean;
2425
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
2527
import org.springframework.http.server.reactive.HttpHandler;
2628
import org.springframework.web.reactive.function.server.RouterFunction;
2729
import org.springframework.web.reactive.function.server.ServerResponse;
@@ -56,6 +58,18 @@ void shouldConfigureHttpHandlerAnnotation() {
5658
.run((context) -> assertThat(context).hasSingleBean(HttpHandler.class));
5759
}
5860

61+
@Test
62+
void shouldConfigureBasePathCompositeHandler() {
63+
this.contextRunner.withConfiguration(AutoConfigurations.of(WebFluxAutoConfiguration.class))
64+
.withPropertyValues("spring.webflux.base-path=/something").run((context) -> {
65+
assertThat(context).hasSingleBean(HttpHandler.class);
66+
HttpHandler httpHandler = context.getBean(HttpHandler.class);
67+
assertThat(httpHandler).isInstanceOf(ContextPathCompositeHandler.class)
68+
.extracting("handlerMap", InstanceOfAssertFactories.map(String.class, HttpHandler.class))
69+
.containsKey("/something");
70+
});
71+
}
72+
5973
@Configuration(proxyBeanMethods = false)
6074
static class CustomHttpHandler {
6175

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.web.reactive;
18+
19+
import java.util.Collections;
20+
import java.util.Map;
21+
22+
import org.junit.jupiter.api.Test;
23+
24+
import org.springframework.boot.context.properties.bind.Bindable;
25+
import org.springframework.boot.context.properties.bind.Binder;
26+
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
27+
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
31+
/**
32+
* Tests for {@link WebFluxProperties}
33+
*
34+
* @author Brian Clozel
35+
*/
36+
class WebFluxPropertiesTests {
37+
38+
private final WebFluxProperties properties = new WebFluxProperties();
39+
40+
@Test
41+
void shouldPrefixBasePathWithMissingSlash() {
42+
bind("spring.webflux.base-path", "something");
43+
assertThat(this.properties.getBasePath()).isEqualTo("/something");
44+
}
45+
46+
@Test
47+
void shouldRemoveTrailingSlashFromBasePath() {
48+
bind("spring.webflux.base-path", "/something/");
49+
assertThat(this.properties.getBasePath()).isEqualTo("/something");
50+
}
51+
52+
private void bind(String name, String value) {
53+
bind(Collections.singletonMap(name, value));
54+
}
55+
56+
private void bind(Map<String, String> map) {
57+
ConfigurationPropertySource source = new MapConfigurationPropertySource(map);
58+
new Binder(source).bind("spring.webflux", Bindable.ofInstance(this.properties));
59+
}
60+
61+
}

0 commit comments

Comments
 (0)