Support path discovery for main dispatcher servlet
Add an `DispatcherServletPath` interface which provides a much more
consistent way to discover the path of the main dispatcher servet.
Prior to this commit, auto-configurations would often make use of the
`ServerProperties` class to discover the dispatcher servlet path. This
mechanism isn't very explicit and also makes it hard for us to relocate
that property in Spring Boot 2.1.
This commit also reverts most of fddc9e9c7e since it is now clear that
the supporting multiple dispatcher servlet paths will be much more
involved that we originally anticipated.
Closes gh-13834
This commit is contained in:
parent
d37e717500
commit
9a9111af21
|
|
@ -16,9 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
|
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.glassfish.jersey.server.ResourceConfig;
|
import org.glassfish.jersey.server.ResourceConfig;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.autoconfigure.endpoint.ExposeExcludePropertyEndpointFilter;
|
import org.springframework.boot.actuate.autoconfigure.endpoint.ExposeExcludePropertyEndpointFilter;
|
||||||
|
|
@ -30,11 +27,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPathProvider;
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.servlet.DispatcherServlet;
|
import org.springframework.web.servlet.DispatcherServlet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -72,27 +68,13 @@ public class ServletEndpointManagementContextConfiguration {
|
||||||
public ServletEndpointRegistrar servletEndpointRegistrar(
|
public ServletEndpointRegistrar servletEndpointRegistrar(
|
||||||
WebEndpointProperties properties,
|
WebEndpointProperties properties,
|
||||||
ServletEndpointsSupplier servletEndpointsSupplier) {
|
ServletEndpointsSupplier servletEndpointsSupplier) {
|
||||||
DispatcherServletPathProvider servletPathProvider = this.context
|
DispatcherServletPath dispatcherServletPath = this.context
|
||||||
.getBean(DispatcherServletPathProvider.class);
|
.getBean(DispatcherServletPath.class);
|
||||||
Set<String> cleanedPaths = getServletPaths(properties, servletPathProvider);
|
return new ServletEndpointRegistrar(
|
||||||
return new ServletEndpointRegistrar(cleanedPaths,
|
dispatcherServletPath.getRelativePath(properties.getBasePath()),
|
||||||
servletEndpointsSupplier.getEndpoints());
|
servletEndpointsSupplier.getEndpoints());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> getServletPaths(WebEndpointProperties properties,
|
|
||||||
DispatcherServletPathProvider servletPathProvider) {
|
|
||||||
return servletPathProvider.getServletPaths().stream()
|
|
||||||
.map((p) -> cleanServletPath(p) + properties.getBasePath())
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String cleanServletPath(String servletPath) {
|
|
||||||
if (StringUtils.hasText(servletPath) && servletPath.endsWith("/")) {
|
|
||||||
return servletPath.substring(0, servletPath.length() - 1);
|
|
||||||
}
|
|
||||||
return servletPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPathProvider;
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
|
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
|
||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
@ -137,23 +137,20 @@ public final class EndpointRequest {
|
||||||
|
|
||||||
private RequestMatcher createDelegate(WebApplicationContext context) {
|
private RequestMatcher createDelegate(WebApplicationContext context) {
|
||||||
try {
|
try {
|
||||||
Set<String> servletPaths = getServletPaths(context);
|
String pathPrefix = getPathPrefix(context);
|
||||||
RequestMatcherFactory requestMatcherFactory = new RequestMatcherFactory(
|
return createDelegate(context, new RequestMatcherFactory(pathPrefix));
|
||||||
servletPaths);
|
|
||||||
return createDelegate(context, requestMatcherFactory);
|
|
||||||
}
|
}
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
return EMPTY_MATCHER;
|
return EMPTY_MATCHER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> getServletPaths(WebApplicationContext context) {
|
private String getPathPrefix(WebApplicationContext context) {
|
||||||
try {
|
try {
|
||||||
return context.getBean(DispatcherServletPathProvider.class)
|
return context.getBean(DispatcherServletPath.class).getPrefix();
|
||||||
.getServletPaths();
|
|
||||||
}
|
}
|
||||||
catch (NoSuchBeanDefinitionException ex) {
|
catch (NoSuchBeanDefinitionException ex) {
|
||||||
return Collections.singleton("");
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,7 +222,7 @@ public final class EndpointRequest {
|
||||||
requestMatcherFactory, paths);
|
requestMatcherFactory, paths);
|
||||||
if (this.includeLinks
|
if (this.includeLinks
|
||||||
&& StringUtils.hasText(pathMappedEndpoints.getBasePath())) {
|
&& StringUtils.hasText(pathMappedEndpoints.getBasePath())) {
|
||||||
delegateMatchers.addAll(
|
delegateMatchers.add(
|
||||||
requestMatcherFactory.antPath(pathMappedEndpoints.getBasePath()));
|
requestMatcherFactory.antPath(pathMappedEndpoints.getBasePath()));
|
||||||
}
|
}
|
||||||
return new OrRequestMatcher(delegateMatchers);
|
return new OrRequestMatcher(delegateMatchers);
|
||||||
|
|
@ -258,8 +255,7 @@ public final class EndpointRequest {
|
||||||
private List<RequestMatcher> getDelegateMatchers(
|
private List<RequestMatcher> getDelegateMatchers(
|
||||||
RequestMatcherFactory requestMatcherFactory, Set<String> paths) {
|
RequestMatcherFactory requestMatcherFactory, Set<String> paths) {
|
||||||
return paths.stream()
|
return paths.stream()
|
||||||
.flatMap(
|
.map((path) -> requestMatcherFactory.antPath(path, "/**"))
|
||||||
(path) -> requestMatcherFactory.antPath(path, "/**").stream())
|
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,9 +272,7 @@ public final class EndpointRequest {
|
||||||
WebEndpointProperties properties = context
|
WebEndpointProperties properties = context
|
||||||
.getBean(WebEndpointProperties.class);
|
.getBean(WebEndpointProperties.class);
|
||||||
if (StringUtils.hasText(properties.getBasePath())) {
|
if (StringUtils.hasText(properties.getBasePath())) {
|
||||||
List<RequestMatcher> matchers = requestMatcherFactory
|
return requestMatcherFactory.antPath(properties.getBasePath());
|
||||||
.antPath(properties.getBasePath());
|
|
||||||
return new OrRequestMatcher(matchers);
|
|
||||||
}
|
}
|
||||||
return EMPTY_MATCHER;
|
return EMPTY_MATCHER;
|
||||||
}
|
}
|
||||||
|
|
@ -290,19 +284,18 @@ public final class EndpointRequest {
|
||||||
*/
|
*/
|
||||||
private static class RequestMatcherFactory {
|
private static class RequestMatcherFactory {
|
||||||
|
|
||||||
private final Set<String> servletPaths = new LinkedHashSet<>();
|
private final String prefix;
|
||||||
|
|
||||||
RequestMatcherFactory(Set<String> servletPaths) {
|
RequestMatcherFactory(String prefix) {
|
||||||
this.servletPaths.addAll(servletPaths);
|
this.prefix = prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RequestMatcher> antPath(String... parts) {
|
public RequestMatcher antPath(String... parts) {
|
||||||
return this.servletPaths.stream()
|
String pattern = this.prefix;
|
||||||
.map((p) -> (StringUtils.hasText(p) && !p.equals("/") ? p : ""))
|
for (String part : parts) {
|
||||||
.distinct()
|
pattern += part;
|
||||||
.map((path) -> Arrays.stream(parts)
|
}
|
||||||
.collect(Collectors.joining("", path, "")))
|
return new AntPathRequestMatcher(pattern);
|
||||||
.map(AntPathRequestMatcher::new).collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.autoconfigure.web.servlet;
|
package org.springframework.boot.actuate.autoconfigure.web.servlet;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.ListableBeanFactory;
|
import org.springframework.beans.factory.ListableBeanFactory;
|
||||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
|
||||||
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
|
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
|
||||||
|
|
@ -27,7 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPathProvider;
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
|
||||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||||
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
|
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
@ -72,6 +70,12 @@ class WebMvcEndpointChildContextConfiguration {
|
||||||
return dispatcherServlet;
|
return dispatcherServlet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
|
||||||
|
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(
|
||||||
|
DispatcherServlet dispatcherServlet) {
|
||||||
|
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
|
||||||
|
}
|
||||||
|
|
||||||
@Bean(name = DispatcherServlet.HANDLER_MAPPING_BEAN_NAME)
|
@Bean(name = DispatcherServlet.HANDLER_MAPPING_BEAN_NAME)
|
||||||
public CompositeHandlerMapping compositeHandlerMapping() {
|
public CompositeHandlerMapping compositeHandlerMapping() {
|
||||||
return new CompositeHandlerMapping();
|
return new CompositeHandlerMapping();
|
||||||
|
|
@ -95,9 +99,4 @@ class WebMvcEndpointChildContextConfiguration {
|
||||||
return new OrderedRequestContextFilter();
|
return new OrderedRequestContextFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public DispatcherServletPathProvider childDispatcherServletPathProvider() {
|
|
||||||
return () -> Collections.singleton("");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,15 +17,13 @@
|
||||||
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
|
package org.springframework.boot.actuate.autoconfigure.endpoint.web;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.glassfish.jersey.server.ResourceConfig;
|
import org.glassfish.jersey.server.ResourceConfig;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
|
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
|
||||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPathProvider;
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
|
@ -50,22 +48,18 @@ public class ServletEndpointManagementContextConfigurationTests {
|
||||||
.withUserConfiguration(TestConfig.class);
|
.withUserConfiguration(TestConfig.class);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void contextShouldContainServletEndpointRegistrar() {
|
public void contextShouldContainServletEndpointRegistrar() {
|
||||||
FilteredClassLoader classLoader = new FilteredClassLoader(ResourceConfig.class);
|
FilteredClassLoader classLoader = new FilteredClassLoader(ResourceConfig.class);
|
||||||
this.contextRunner.withClassLoader(classLoader).run((context) -> {
|
this.contextRunner.withClassLoader(classLoader).run((context) -> {
|
||||||
assertThat(context).hasSingleBean(ServletEndpointRegistrar.class);
|
assertThat(context).hasSingleBean(ServletEndpointRegistrar.class);
|
||||||
ServletEndpointRegistrar bean = context
|
ServletEndpointRegistrar bean = context
|
||||||
.getBean(ServletEndpointRegistrar.class);
|
.getBean(ServletEndpointRegistrar.class);
|
||||||
Set<String> basePaths = (Set<String>) ReflectionTestUtils.getField(bean,
|
String basePath = (String) ReflectionTestUtils.getField(bean, "basePath");
|
||||||
"basePaths");
|
assertThat(basePath).isEqualTo("/test/actuator");
|
||||||
assertThat(basePaths).containsExactlyInAnyOrder("/test/actuator", "/actuator",
|
|
||||||
"/foo/actuator");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void servletPathShouldNotAffectJerseyConfiguration() {
|
public void servletPathShouldNotAffectJerseyConfiguration() {
|
||||||
FilteredClassLoader classLoader = new FilteredClassLoader(
|
FilteredClassLoader classLoader = new FilteredClassLoader(
|
||||||
DispatcherServlet.class);
|
DispatcherServlet.class);
|
||||||
|
|
@ -73,9 +67,8 @@ public class ServletEndpointManagementContextConfigurationTests {
|
||||||
assertThat(context).hasSingleBean(ServletEndpointRegistrar.class);
|
assertThat(context).hasSingleBean(ServletEndpointRegistrar.class);
|
||||||
ServletEndpointRegistrar bean = context
|
ServletEndpointRegistrar bean = context
|
||||||
.getBean(ServletEndpointRegistrar.class);
|
.getBean(ServletEndpointRegistrar.class);
|
||||||
Set<String> basePaths = (Set<String>) ReflectionTestUtils.getField(bean,
|
String basePath = (String) ReflectionTestUtils.getField(bean, "basePath");
|
||||||
"basePaths");
|
assertThat(basePath).isEqualTo("/actuator");
|
||||||
assertThat(basePaths).containsExactly("/actuator");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,14 +90,8 @@ public class ServletEndpointManagementContextConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DispatcherServletPathProvider servletPathProvider() {
|
public DispatcherServletPath dispatcherServletPath() {
|
||||||
return () -> {
|
return () -> "/test";
|
||||||
Set<String> paths = new LinkedHashSet<>();
|
|
||||||
paths.add("/");
|
|
||||||
paths.add("/test");
|
|
||||||
paths.add("/foo/");
|
|
||||||
return paths;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
@ -33,7 +31,7 @@ import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;
|
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoint;
|
||||||
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
|
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpoint;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPathProvider;
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockServletContext;
|
import org.springframework.mock.web.MockServletContext;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
|
|
@ -78,12 +76,11 @@ public class EndpointRequestTests {
|
||||||
@Test
|
@Test
|
||||||
public void toAnyEndpointWhenServletPathNotEmptyShouldMatch() {
|
public void toAnyEndpointWhenServletPathNotEmptyShouldMatch() {
|
||||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||||
assertMatcher(matcher, "/actuator", "/spring", "/admin")
|
assertMatcher(matcher, "/actuator", "/spring").matches("/spring",
|
||||||
.matches(Arrays.asList("/spring", "/admin"), "/actuator/foo");
|
"/actuator/foo");
|
||||||
assertMatcher(matcher, "/actuator", "/spring", "/admin")
|
assertMatcher(matcher, "/actuator", "/spring").matches("/spring",
|
||||||
.matches(Arrays.asList("/spring", "/admin"), "/actuator/bar");
|
"/actuator/bar");
|
||||||
assertMatcher(matcher, "/actuator", "/spring").matches(Arrays.asList("/spring"),
|
assertMatcher(matcher, "/actuator", "/spring").matches("/spring", "/actuator");
|
||||||
"/actuator");
|
|
||||||
assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("/spring",
|
assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("/spring",
|
||||||
"/actuator/baz");
|
"/actuator/baz");
|
||||||
assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("", "/actuator/foo");
|
assertMatcher(matcher, "/actuator", "/spring").doesNotMatch("", "/actuator/foo");
|
||||||
|
|
@ -92,10 +89,10 @@ public class EndpointRequestTests {
|
||||||
@Test
|
@Test
|
||||||
public void toAnyEndpointWhenDispatcherServletPathProviderNotAvailableUsesEmptyPath() {
|
public void toAnyEndpointWhenDispatcherServletPathProviderNotAvailableUsesEmptyPath() {
|
||||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||||
assertMatcher(matcher, "/actuator", (String) null).matches("/actuator/foo");
|
assertMatcher(matcher, "/actuator", null).matches("/actuator/foo");
|
||||||
assertMatcher(matcher, "/actuator", (String) null).matches("/actuator/bar");
|
assertMatcher(matcher, "/actuator", null).matches("/actuator/bar");
|
||||||
assertMatcher(matcher, "/actuator", (String) null).matches("/actuator");
|
assertMatcher(matcher, "/actuator", null).matches("/actuator");
|
||||||
assertMatcher(matcher, "/actuator", (String) null).doesNotMatch("/actuator/baz");
|
assertMatcher(matcher, "/actuator", null).doesNotMatch("/actuator/baz");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -222,8 +219,8 @@ public class EndpointRequestTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath,
|
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, String basePath,
|
||||||
String... servletPaths) {
|
String servletPath) {
|
||||||
return assertMatcher(matcher, mockPathMappedEndpoints(basePath), servletPaths);
|
return assertMatcher(matcher, mockPathMappedEndpoints(basePath), servletPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PathMappedEndpoints mockPathMappedEndpoints(String basePath) {
|
private PathMappedEndpoints mockPathMappedEndpoints(String basePath) {
|
||||||
|
|
@ -246,7 +243,7 @@ public class EndpointRequestTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
||||||
PathMappedEndpoints pathMappedEndpoints, String... servletPaths) {
|
PathMappedEndpoints pathMappedEndpoints, String dispatcherServletPath) {
|
||||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||||
context.registerBean(WebEndpointProperties.class);
|
context.registerBean(WebEndpointProperties.class);
|
||||||
if (pathMappedEndpoints != null) {
|
if (pathMappedEndpoints != null) {
|
||||||
|
|
@ -257,10 +254,9 @@ public class EndpointRequestTests {
|
||||||
properties.setBasePath(pathMappedEndpoints.getBasePath());
|
properties.setBasePath(pathMappedEndpoints.getBasePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (servletPaths != null) {
|
if (dispatcherServletPath != null) {
|
||||||
DispatcherServletPathProvider pathProvider = () -> new LinkedHashSet<>(
|
DispatcherServletPath path = () -> dispatcherServletPath;
|
||||||
Arrays.asList(servletPaths));
|
context.registerBean(DispatcherServletPath.class, () -> path);
|
||||||
context.registerBean(DispatcherServletPathProvider.class, () -> pathProvider);
|
|
||||||
}
|
}
|
||||||
return assertThat(new RequestMatcherAssert(context, matcher));
|
return assertThat(new RequestMatcherAssert(context, matcher));
|
||||||
}
|
}
|
||||||
|
|
@ -280,8 +276,8 @@ public class EndpointRequestTests {
|
||||||
matches(mockRequest(servletPath));
|
matches(mockRequest(servletPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void matches(List<String> servletPaths, String pathInfo) {
|
public void matches(String servletPath, String pathInfo) {
|
||||||
servletPaths.forEach((p) -> matches(mockRequest(p, pathInfo)));
|
matches(mockRequest(servletPath, pathInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void matches(HttpServletRequest request) {
|
private void matches(HttpServletRequest request) {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.web.servlet;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPathProvider;
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||||
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
|
import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
@ -64,12 +64,12 @@ public class WebMvcEndpointChildContextConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void contextShouldConfigureDispatcherServletPathProviderWithEmptyPath() {
|
public void contextShouldConfigureDispatcherServletPathWithRootPath() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withUserConfiguration(WebMvcEndpointChildContextConfiguration.class)
|
.withUserConfiguration(WebMvcEndpointChildContextConfiguration.class)
|
||||||
.run((context) -> assertThat(context
|
.run((context) -> assertThat(
|
||||||
.getBean(DispatcherServletPathProvider.class).getServletPaths())
|
context.getBean(DispatcherServletPath.class).getPath())
|
||||||
.containsExactly(""));
|
.isEqualTo("/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ExistingConfig {
|
static class ExistingConfig {
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.endpoint.web;
|
package org.springframework.boot.actuate.endpoint.web;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
|
|
@ -30,7 +27,6 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ServletContextInitializer} to register {@link ExposableServletEndpoint servlet
|
* {@link ServletContextInitializer} to register {@link ExposableServletEndpoint servlet
|
||||||
|
|
@ -44,24 +40,14 @@ public class ServletEndpointRegistrar implements ServletContextInitializer {
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ServletEndpointRegistrar.class);
|
private static final Log logger = LogFactory.getLog(ServletEndpointRegistrar.class);
|
||||||
|
|
||||||
private final Set<String> basePaths = new LinkedHashSet<>();
|
private final String basePath;
|
||||||
|
|
||||||
private final Collection<ExposableServletEndpoint> servletEndpoints;
|
private final Collection<ExposableServletEndpoint> servletEndpoints;
|
||||||
|
|
||||||
public ServletEndpointRegistrar(String basePath,
|
public ServletEndpointRegistrar(String basePath,
|
||||||
Collection<ExposableServletEndpoint> servletEndpoints) {
|
Collection<ExposableServletEndpoint> servletEndpoints) {
|
||||||
Assert.notNull(servletEndpoints, "ServletEndpoints must not be null");
|
Assert.notNull(servletEndpoints, "ServletEndpoints must not be null");
|
||||||
this.basePaths.add((basePath != null ? basePath : ""));
|
this.basePath = (basePath != null ? basePath : "");
|
||||||
this.servletEndpoints = servletEndpoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServletEndpointRegistrar(Set<String> basePaths,
|
|
||||||
Collection<ExposableServletEndpoint> servletEndpoints) {
|
|
||||||
Assert.notNull(servletEndpoints, "ServletEndpoints must not be null");
|
|
||||||
this.basePaths.addAll(basePaths);
|
|
||||||
if (CollectionUtils.isEmpty(this.basePaths)) {
|
|
||||||
this.basePaths.add("");
|
|
||||||
}
|
|
||||||
this.servletEndpoints = servletEndpoints;
|
this.servletEndpoints = servletEndpoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,24 +60,14 @@ public class ServletEndpointRegistrar implements ServletContextInitializer {
|
||||||
private void register(ServletContext servletContext,
|
private void register(ServletContext servletContext,
|
||||||
ExposableServletEndpoint endpoint) {
|
ExposableServletEndpoint endpoint) {
|
||||||
String name = endpoint.getId() + "-actuator-endpoint";
|
String name = endpoint.getId() + "-actuator-endpoint";
|
||||||
|
String path = this.basePath + "/" + endpoint.getRootPath();
|
||||||
|
String urlMapping = (path.endsWith("/") ? path + "*" : path + "/*");
|
||||||
EndpointServlet endpointServlet = endpoint.getEndpointServlet();
|
EndpointServlet endpointServlet = endpoint.getEndpointServlet();
|
||||||
Dynamic registration = servletContext.addServlet(name,
|
Dynamic registration = servletContext.addServlet(name,
|
||||||
endpointServlet.getServlet());
|
endpointServlet.getServlet());
|
||||||
String[] urlMappings = getUrlMappings(endpoint.getRootPath());
|
registration.addMapping(urlMapping);
|
||||||
registration.addMapping(urlMappings);
|
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
Arrays.stream(urlMappings).forEach(
|
|
||||||
(mapping) -> logger.info("Registered '" + mapping + "' to " + name));
|
|
||||||
}
|
|
||||||
registration.setInitParameters(endpointServlet.getInitParameters());
|
registration.setInitParameters(endpointServlet.getInitParameters());
|
||||||
}
|
logger.info("Registered '" + path + "' to " + name);
|
||||||
|
|
||||||
private String[] getUrlMappings(String endpointPath) {
|
|
||||||
return this.basePaths.stream()
|
|
||||||
.map((basePath) -> (basePath != null ? basePath + "/" + endpointPath
|
|
||||||
: "/" + endpointPath))
|
|
||||||
.distinct().map((path) -> (path.endsWith("/") ? path + "*" : path + "/*"))
|
|
||||||
.toArray(String[]::new);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@ package org.springframework.boot.actuate.endpoint.web;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.servlet.GenericServlet;
|
import javax.servlet.GenericServlet;
|
||||||
import javax.servlet.Servlet;
|
import javax.servlet.Servlet;
|
||||||
|
|
@ -49,7 +47,6 @@ import static org.mockito.Mockito.verify;
|
||||||
* Tests for {@link ServletEndpointRegistrar}.
|
* Tests for {@link ServletEndpointRegistrar}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Madhura Bhave
|
|
||||||
*/
|
*/
|
||||||
public class ServletEndpointRegistrarTests {
|
public class ServletEndpointRegistrarTests {
|
||||||
|
|
||||||
|
|
@ -76,14 +73,14 @@ public class ServletEndpointRegistrarTests {
|
||||||
public void createWhenServletEndpointsIsNullShouldThrowException() {
|
public void createWhenServletEndpointsIsNullShouldThrowException() {
|
||||||
this.thrown.expect(IllegalArgumentException.class);
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
this.thrown.expectMessage("ServletEndpoints must not be null");
|
this.thrown.expectMessage("ServletEndpoints must not be null");
|
||||||
new ServletEndpointRegistrar((String) null, null);
|
new ServletEndpointRegistrar(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStartupShouldRegisterServlets() throws Exception {
|
public void onStartupShouldRegisterServlets() throws Exception {
|
||||||
ExposableServletEndpoint endpoint = mockEndpoint(
|
ExposableServletEndpoint endpoint = mockEndpoint(
|
||||||
new EndpointServlet(TestServlet.class));
|
new EndpointServlet(TestServlet.class));
|
||||||
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar((String) null,
|
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(null,
|
||||||
Collections.singleton(endpoint));
|
Collections.singleton(endpoint));
|
||||||
registrar.onStartup(this.servletContext);
|
registrar.onStartup(this.servletContext);
|
||||||
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
|
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
|
||||||
|
|
@ -105,64 +102,6 @@ public class ServletEndpointRegistrarTests {
|
||||||
verify(this.dynamic).addMapping("/actuator/test/*");
|
verify(this.dynamic).addMapping("/actuator/test/*");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onStartupWhenHasMultipleBasePathsShouldIncludeAllBasePaths()
|
|
||||||
throws Exception {
|
|
||||||
ExposableServletEndpoint endpoint = mockEndpoint(
|
|
||||||
new EndpointServlet(TestServlet.class));
|
|
||||||
Set<String> basePaths = new LinkedHashSet<>();
|
|
||||||
basePaths.add("/actuator");
|
|
||||||
basePaths.add("/admin");
|
|
||||||
basePaths.add("/application");
|
|
||||||
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePaths,
|
|
||||||
Collections.singleton(endpoint));
|
|
||||||
registrar.onStartup(this.servletContext);
|
|
||||||
verify(this.servletContext).addServlet(eq("test-actuator-endpoint"),
|
|
||||||
this.servlet.capture());
|
|
||||||
assertThat(this.servlet.getValue()).isInstanceOf(TestServlet.class);
|
|
||||||
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
|
||||||
verify(this.dynamic).addMapping(captor.capture());
|
|
||||||
assertThat(captor.getAllValues()).containsExactlyInAnyOrder("/application/test/*",
|
|
||||||
"/admin/test/*", "/actuator/test/*");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onStartupWhenHasEmptyBasePathsShouldIncludeRoot() throws Exception {
|
|
||||||
ExposableServletEndpoint endpoint = mockEndpoint(
|
|
||||||
new EndpointServlet(TestServlet.class));
|
|
||||||
Set<String> basePaths = Collections.emptySet();
|
|
||||||
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePaths,
|
|
||||||
Collections.singleton(endpoint));
|
|
||||||
registrar.onStartup(this.servletContext);
|
|
||||||
verify(this.dynamic).addMapping("/test/*");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onStartupWhenHasBasePathsHasNullValueShouldIncludeRoot()
|
|
||||||
throws Exception {
|
|
||||||
ExposableServletEndpoint endpoint = mockEndpoint(
|
|
||||||
new EndpointServlet(TestServlet.class));
|
|
||||||
Set<String> basePaths = new LinkedHashSet<>();
|
|
||||||
basePaths.add(null);
|
|
||||||
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePaths,
|
|
||||||
Collections.singleton(endpoint));
|
|
||||||
registrar.onStartup(this.servletContext);
|
|
||||||
verify(this.dynamic).addMapping("/test/*");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onStartupWhenDuplicateValuesShouldIncludeDistinct() throws Exception {
|
|
||||||
ExposableServletEndpoint endpoint = mockEndpoint(
|
|
||||||
new EndpointServlet(TestServlet.class));
|
|
||||||
Set<String> basePaths = new LinkedHashSet<>();
|
|
||||||
basePaths.add("");
|
|
||||||
basePaths.add(null);
|
|
||||||
ServletEndpointRegistrar registrar = new ServletEndpointRegistrar(basePaths,
|
|
||||||
Collections.singleton(endpoint));
|
|
||||||
registrar.onStartup(this.servletContext);
|
|
||||||
verify(this.dynamic).addMapping("/test/*");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStartupWhenHasInitParametersShouldRegisterInitParameters()
|
public void onStartupWhenHasInitParametersShouldRegisterInitParameters()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import java.util.stream.Stream;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
|
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
|
||||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
|
import org.springframework.boot.security.servlet.ApplicationContextRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||||
|
|
@ -96,14 +96,14 @@ public final class StaticResourceRequest {
|
||||||
* Locations}.
|
* Locations}.
|
||||||
*/
|
*/
|
||||||
public static final class StaticResourceRequestMatcher
|
public static final class StaticResourceRequestMatcher
|
||||||
extends ApplicationContextRequestMatcher<ServerProperties> {
|
extends ApplicationContextRequestMatcher<DispatcherServletPath> {
|
||||||
|
|
||||||
private final Set<StaticResourceLocation> locations;
|
private final Set<StaticResourceLocation> locations;
|
||||||
|
|
||||||
private volatile RequestMatcher delegate;
|
private volatile RequestMatcher delegate;
|
||||||
|
|
||||||
private StaticResourceRequestMatcher(Set<StaticResourceLocation> locations) {
|
private StaticResourceRequestMatcher(Set<StaticResourceLocation> locations) {
|
||||||
super(ServerProperties.class);
|
super(DispatcherServletPath.class);
|
||||||
this.locations = locations;
|
this.locations = locations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,25 +134,26 @@ public final class StaticResourceRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialized(Supplier<ServerProperties> serverProperties) {
|
protected void initialized(
|
||||||
|
Supplier<DispatcherServletPath> dispatcherServletPath) {
|
||||||
this.delegate = new OrRequestMatcher(
|
this.delegate = new OrRequestMatcher(
|
||||||
getDelegateMatchers(serverProperties.get()));
|
getDelegateMatchers(dispatcherServletPath.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<RequestMatcher> getDelegateMatchers(
|
private List<RequestMatcher> getDelegateMatchers(
|
||||||
ServerProperties serverProperties) {
|
DispatcherServletPath dispatcherServletPath) {
|
||||||
return getPatterns(serverProperties).map(AntPathRequestMatcher::new)
|
return getPatterns(dispatcherServletPath).map(AntPathRequestMatcher::new)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<String> getPatterns(ServerProperties serverProperties) {
|
private Stream<String> getPatterns(DispatcherServletPath dispatcherServletPath) {
|
||||||
return this.locations.stream().flatMap(StaticResourceLocation::getPatterns)
|
return this.locations.stream().flatMap(StaticResourceLocation::getPatterns)
|
||||||
.map(serverProperties.getServlet()::getPath);
|
.map(dispatcherServletPath::getRelativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean matches(HttpServletRequest request,
|
protected boolean matches(HttpServletRequest request,
|
||||||
Supplier<ServerProperties> context) {
|
Supplier<DispatcherServletPath> context) {
|
||||||
return this.delegate.matches(request);
|
return this.delegate.matches(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,13 @@ public class ServerProperties {
|
||||||
return this.session;
|
return this.session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the mapping used to map a servlet to the path.
|
||||||
|
* @return the servlet mapping
|
||||||
|
* @deprecated since 2.0.4 in favor of
|
||||||
|
* {@link org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath#getServletUrlMapping}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getServletMapping() {
|
public String getServletMapping() {
|
||||||
if (this.path.equals("") || this.path.equals("/")) {
|
if (this.path.equals("") || this.path.equals("/")) {
|
||||||
return "/";
|
return "/";
|
||||||
|
|
@ -282,6 +289,14 @@ public class ServerProperties {
|
||||||
return this.path + "/*";
|
return this.path + "/*";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a path relative to the servlet prefix.
|
||||||
|
* @param path the path to make relative
|
||||||
|
* @return the relative path
|
||||||
|
* @deprecated since 2.0.4 in favor of
|
||||||
|
* {@link org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath#getRelativePath(String)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getPath(String path) {
|
public String getPath(String path) {
|
||||||
String prefix = getServletPrefix();
|
String prefix = getServletPrefix();
|
||||||
if (!path.startsWith("/")) {
|
if (!path.startsWith("/")) {
|
||||||
|
|
@ -290,6 +305,13 @@ public class ServerProperties {
|
||||||
return prefix + path;
|
return prefix + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the servlet prefix.
|
||||||
|
* @return the servlet prefix
|
||||||
|
* @deprecated since 2.0.4 in favor of
|
||||||
|
* {@link org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath#getPrefix()}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getServletPrefix() {
|
public String getServletPrefix() {
|
||||||
String result = this.path;
|
String result = this.path;
|
||||||
int index = result.indexOf('*');
|
int index = result.indexOf('*');
|
||||||
|
|
@ -302,6 +324,14 @@ public class ServerProperties {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a array of relative paths from the given source.
|
||||||
|
* @param paths the source paths
|
||||||
|
* @return the relative paths
|
||||||
|
* @deprecated since 2.0.4 in favor of
|
||||||
|
* {@link org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath#getRelativePath(String)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public String[] getPathsArray(Collection<String> paths) {
|
public String[] getPathsArray(Collection<String> paths) {
|
||||||
String[] result = new String[paths.size()];
|
String[] result = new String[paths.size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
@ -311,6 +341,14 @@ public class ServerProperties {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a array of relative paths from the given source.
|
||||||
|
* @param paths the source paths
|
||||||
|
* @return the relative paths
|
||||||
|
* @deprecated since 2.0.4 in favor of
|
||||||
|
* {@link org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath#getRelativePath(String)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public String[] getPathsArray(String[] paths) {
|
public String[] getPathsArray(String[] paths) {
|
||||||
String[] result = new String[paths.length];
|
String[] result = new String[paths.length];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.boot.autoconfigure.web.servlet;
|
package org.springframework.boot.autoconfigure.web.servlet;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.servlet.MultipartConfigElement;
|
import javax.servlet.MultipartConfigElement;
|
||||||
|
|
@ -34,7 +33,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||||
|
|
@ -139,11 +137,10 @@ public class DispatcherServletAutoConfiguration {
|
||||||
|
|
||||||
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
|
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
|
||||||
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
|
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
|
||||||
public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(
|
public DispatcherServletRegistrationBean dispatcherServletRegistration(
|
||||||
DispatcherServlet dispatcherServlet) {
|
DispatcherServlet dispatcherServlet) {
|
||||||
ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(
|
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(
|
||||||
dispatcherServlet,
|
dispatcherServlet, this.serverProperties.getServlet().getPath());
|
||||||
this.serverProperties.getServlet().getServletMapping());
|
|
||||||
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
|
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
|
||||||
registration.setLoadOnStartup(
|
registration.setLoadOnStartup(
|
||||||
this.webMvcProperties.getServlet().getLoadOnStartup());
|
this.webMvcProperties.getServlet().getLoadOnStartup());
|
||||||
|
|
@ -153,15 +150,6 @@ public class DispatcherServletAutoConfiguration {
|
||||||
return registration;
|
return registration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(DispatcherServletPathProvider.class)
|
|
||||||
@ConditionalOnSingleCandidate(DispatcherServlet.class)
|
|
||||||
public DispatcherServletPathProvider dispatcherServletPathProvider() {
|
|
||||||
return () -> Collections.singleton(
|
|
||||||
DispatcherServletRegistrationConfiguration.this.serverProperties
|
|
||||||
.getServlet().getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Order(Ordered.LOWEST_PRECEDENCE - 10)
|
@Order(Ordered.LOWEST_PRECEDENCE - 10)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2018 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
|
||||||
|
*
|
||||||
|
* http://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 org.springframework.boot.autoconfigure.web.servlet;
|
||||||
|
|
||||||
|
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||||
|
import org.springframework.web.servlet.DispatcherServlet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface that can be used by auto-configurations that need path details for the
|
||||||
|
* {@link DispatcherServletAutoConfiguration#DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME
|
||||||
|
* default} {@link DispatcherServlet}.
|
||||||
|
*
|
||||||
|
* @author Madhura Bhave
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 2.0.4
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface DispatcherServletPath {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the configured path of the dispatcher servlet.
|
||||||
|
* @return the configured path
|
||||||
|
*/
|
||||||
|
String getPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a form of the given path that's relative to the dispatcher servlet path.
|
||||||
|
* @param path the path to make relative
|
||||||
|
* @return the relative path
|
||||||
|
*/
|
||||||
|
default String getRelativePath(String path) {
|
||||||
|
String prefix = getPrefix();
|
||||||
|
if (!path.startsWith("/")) {
|
||||||
|
path = "/" + path;
|
||||||
|
}
|
||||||
|
return prefix + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a cleaned up version of the path that can be used as a prefix for URLs. The
|
||||||
|
* resulting path will have path will not have a trailing slash.
|
||||||
|
* @return the prefix
|
||||||
|
* @see #getRelativePath(String)
|
||||||
|
*/
|
||||||
|
default String getPrefix() {
|
||||||
|
String result = getPath();
|
||||||
|
int index = result.indexOf('*');
|
||||||
|
if (index != -1) {
|
||||||
|
result = result.substring(0, index);
|
||||||
|
}
|
||||||
|
if (result.endsWith("/")) {
|
||||||
|
result = result.substring(0, result.length() - 1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a URL mapping pattern that can be used with a
|
||||||
|
* {@link ServletRegistrationBean} to map the dispatcher servlet.
|
||||||
|
* @return the path as a servlet URL mapping
|
||||||
|
*/
|
||||||
|
default String getServletUrlMapping() {
|
||||||
|
if (getPath().equals("") || getPath().equals("/")) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
if (getPath().contains("*")) {
|
||||||
|
return getPath();
|
||||||
|
}
|
||||||
|
if (getPath().endsWith("/")) {
|
||||||
|
return getPath() + "*";
|
||||||
|
}
|
||||||
|
return getPath() + "/*";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.web.servlet;
|
package org.springframework.boot.autoconfigure.web.servlet;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.web.servlet.DispatcherServlet;
|
import org.springframework.web.servlet.DispatcherServlet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -26,10 +24,13 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||||
*
|
*
|
||||||
* @author Madhura Bhave
|
* @author Madhura Bhave
|
||||||
* @since 2.0.2
|
* @since 2.0.2
|
||||||
|
* @deprecated since 2.0.4 in favor of {@link DispatcherServletPath} and
|
||||||
|
* {@link DispatcherServletRegistrationBean}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface DispatcherServletPathProvider {
|
public interface DispatcherServletPathProvider {
|
||||||
|
|
||||||
Set<String> getServletPaths();
|
String getServletPath();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2018 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
|
||||||
|
*
|
||||||
|
* http://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 org.springframework.boot.autoconfigure.web.servlet;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.web.servlet.DispatcherServlet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ServletRegistrationBean} for the auto-configured {@link DispatcherServlet}. Both
|
||||||
|
* registeres the servlet and exposes {@link DispatcherServletPath} information.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
* @since 2.0.4
|
||||||
|
*/
|
||||||
|
public class DispatcherServletRegistrationBean extends
|
||||||
|
ServletRegistrationBean<DispatcherServlet> implements DispatcherServletPath {
|
||||||
|
|
||||||
|
private final String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link DispatcherServletRegistrationBean} instance for the given
|
||||||
|
* servlet and path.
|
||||||
|
* @param servlet the dispatcher servlet
|
||||||
|
* @param path the dispatcher servlet path
|
||||||
|
*/
|
||||||
|
public DispatcherServletRegistrationBean(DispatcherServlet servlet, String path) {
|
||||||
|
super(servlet);
|
||||||
|
Assert.notNull(path, "Path must not be null");
|
||||||
|
this.path = path;
|
||||||
|
super.addUrlMappings(getServletUrlMapping());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPath() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUrlMappings(Collection<String> urlMappings) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"URL Mapping cannot be changed on a DispatcherServlet registration");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUrlMappings(String... urlMappings) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"URL Mapping cannot be changed on a DispatcherServlet registration");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -49,6 +49,7 @@ import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvi
|
||||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
||||||
import org.springframework.boot.autoconfigure.web.ResourceProperties;
|
import org.springframework.boot.autoconfigure.web.ResourceProperties;
|
||||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.web.server.ErrorPage;
|
import org.springframework.boot.web.server.ErrorPage;
|
||||||
|
|
@ -94,11 +95,15 @@ public class ErrorMvcAutoConfiguration {
|
||||||
|
|
||||||
private final ServerProperties serverProperties;
|
private final ServerProperties serverProperties;
|
||||||
|
|
||||||
|
private final DispatcherServletPath dispatcherServletPath;
|
||||||
|
|
||||||
private final List<ErrorViewResolver> errorViewResolvers;
|
private final List<ErrorViewResolver> errorViewResolvers;
|
||||||
|
|
||||||
public ErrorMvcAutoConfiguration(ServerProperties serverProperties,
|
public ErrorMvcAutoConfiguration(ServerProperties serverProperties,
|
||||||
|
DispatcherServletPath dispatcherServletPath,
|
||||||
ObjectProvider<List<ErrorViewResolver>> errorViewResolversProvider) {
|
ObjectProvider<List<ErrorViewResolver>> errorViewResolversProvider) {
|
||||||
this.serverProperties = serverProperties;
|
this.serverProperties = serverProperties;
|
||||||
|
this.dispatcherServletPath = dispatcherServletPath;
|
||||||
this.errorViewResolvers = errorViewResolversProvider.getIfAvailable();
|
this.errorViewResolvers = errorViewResolversProvider.getIfAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +123,7 @@ public class ErrorMvcAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ErrorPageCustomizer errorPageCustomizer() {
|
public ErrorPageCustomizer errorPageCustomizer() {
|
||||||
return new ErrorPageCustomizer(this.serverProperties);
|
return new ErrorPageCustomizer(this.serverProperties, this.dispatcherServletPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
@ -327,15 +332,18 @@ public class ErrorMvcAutoConfiguration {
|
||||||
|
|
||||||
private final ServerProperties properties;
|
private final ServerProperties properties;
|
||||||
|
|
||||||
protected ErrorPageCustomizer(ServerProperties properties) {
|
private final DispatcherServletPath dispatcherServletPath;
|
||||||
|
|
||||||
|
protected ErrorPageCustomizer(ServerProperties properties,
|
||||||
|
DispatcherServletPath dispatcherServletPath) {
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
this.dispatcherServletPath = dispatcherServletPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
|
public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
|
||||||
ErrorPage errorPage = new ErrorPage(
|
ErrorPage errorPage = new ErrorPage(this.dispatcherServletPath
|
||||||
this.properties.getServlet().getServletPrefix()
|
.getRelativePath(this.properties.getError().getPath()));
|
||||||
+ this.properties.getError().getPath());
|
|
||||||
errorPageRegistry.addErrorPages(errorPage);
|
errorPageRegistry.addErrorPages(errorPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
|
import org.springframework.boot.autoconfigure.security.StaticResourceLocation;
|
||||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockServletContext;
|
import org.springframework.mock.web.MockServletContext;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
|
|
@ -96,15 +97,20 @@ public class StaticResourceRequestTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher) {
|
private RequestMatcherAssert assertMatcher(RequestMatcher matcher) {
|
||||||
|
DispatcherServletPath dispatcherServletPath = () -> "";
|
||||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||||
context.registerBean(ServerProperties.class);
|
context.registerBean(ServerProperties.class);
|
||||||
|
context.registerBean(DispatcherServletPath.class, () -> dispatcherServletPath);
|
||||||
return assertThat(new RequestMatcherAssert(context, matcher));
|
return assertThat(new RequestMatcherAssert(context, matcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
|
||||||
ServerProperties serverProperties) {
|
ServerProperties serverProperties) {
|
||||||
|
DispatcherServletPath dispatcherServletPath = () -> serverProperties.getServlet()
|
||||||
|
.getPath();
|
||||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||||
context.registerBean(ServerProperties.class, () -> serverProperties);
|
context.registerBean(ServerProperties.class, () -> serverProperties);
|
||||||
|
context.registerBean(DispatcherServletPath.class, () -> dispatcherServletPath);
|
||||||
return assertThat(new RequestMatcherAssert(context, matcher));
|
return assertThat(new RequestMatcherAssert(context, matcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ public class ServerPropertiesTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Deprecated
|
||||||
public void testServletPathAsMapping() {
|
public void testServletPathAsMapping() {
|
||||||
bind("server.servlet.path", "/foo/*");
|
bind("server.servlet.path", "/foo/*");
|
||||||
assertThat(this.properties.getServlet().getServletMapping()).isEqualTo("/foo/*");
|
assertThat(this.properties.getServlet().getServletMapping()).isEqualTo("/foo/*");
|
||||||
|
|
@ -86,6 +87,7 @@ public class ServerPropertiesTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Deprecated
|
||||||
public void testServletPathAsPrefix() {
|
public void testServletPathAsPrefix() {
|
||||||
bind("server.servlet.path", "/foo");
|
bind("server.servlet.path", "/foo");
|
||||||
assertThat(this.properties.getServlet().getServletMapping()).isEqualTo("/foo/*");
|
assertThat(this.properties.getServlet().getServletMapping()).isEqualTo("/foo/*");
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,7 @@ public class DispatcherServletAutoConfigurationTests {
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
assertThat(context).doesNotHaveBean(ServletRegistrationBean.class);
|
assertThat(context).doesNotHaveBean(ServletRegistrationBean.class);
|
||||||
assertThat(context).doesNotHaveBean(DispatcherServlet.class);
|
assertThat(context).doesNotHaveBean(DispatcherServlet.class);
|
||||||
assertThat(context)
|
assertThat(context).doesNotHaveBean(DispatcherServletPath.class);
|
||||||
.doesNotHaveBean(DispatcherServletPathProvider.class);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +76,7 @@ public class DispatcherServletAutoConfigurationTests {
|
||||||
public void registrationOverrideWithDispatcherServletWrongName() {
|
public void registrationOverrideWithDispatcherServletWrongName() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withUserConfiguration(CustomDispatcherServletDifferentName.class,
|
.withUserConfiguration(CustomDispatcherServletDifferentName.class,
|
||||||
CustomDispatcherServletPathProvider.class)
|
CustomDispatcherServletPath.class)
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
ServletRegistrationBean<?> registration = context
|
ServletRegistrationBean<?> registration = context
|
||||||
.getBean(ServletRegistrationBean.class);
|
.getBean(ServletRegistrationBean.class);
|
||||||
|
|
@ -91,7 +90,7 @@ public class DispatcherServletAutoConfigurationTests {
|
||||||
@Test
|
@Test
|
||||||
public void registrationOverrideWithAutowiredServlet() {
|
public void registrationOverrideWithAutowiredServlet() {
|
||||||
this.contextRunner.withUserConfiguration(CustomAutowiredRegistration.class,
|
this.contextRunner.withUserConfiguration(CustomAutowiredRegistration.class,
|
||||||
CustomDispatcherServletPathProvider.class).run((context) -> {
|
CustomDispatcherServletPath.class).run((context) -> {
|
||||||
ServletRegistrationBean<?> registration = context
|
ServletRegistrationBean<?> registration = context
|
||||||
.getBean(ServletRegistrationBean.class);
|
.getBean(ServletRegistrationBean.class);
|
||||||
assertThat(registration.getUrlMappings()).containsExactly("/foo");
|
assertThat(registration.getUrlMappings()).containsExactly("/foo");
|
||||||
|
|
@ -111,43 +110,35 @@ public class DispatcherServletAutoConfigurationTests {
|
||||||
assertThat(registration.getUrlMappings())
|
assertThat(registration.getUrlMappings())
|
||||||
.containsExactly("/spring/*");
|
.containsExactly("/spring/*");
|
||||||
assertThat(registration.getMultipartConfig()).isNull();
|
assertThat(registration.getMultipartConfig()).isNull();
|
||||||
assertThat(context.getBean(DispatcherServletPathProvider.class)
|
assertThat(context.getBean(DispatcherServletPath.class).getPath())
|
||||||
.getServletPaths()).containsExactly("/spring");
|
.isEqualTo("/spring");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void pathProviderNotCreatedWhenMultipleDispatcherServletsPresent() {
|
public void dispatcherServletPathWhenCustomDispatcherServletSameNameShouldReturnConfiguredServletPath() {
|
||||||
this.contextRunner
|
|
||||||
.withUserConfiguration(CustomDispatcherServletDifferentName.class)
|
|
||||||
.run((context) -> assertThat(context)
|
|
||||||
.doesNotHaveBean(DispatcherServletPathProvider.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void pathProviderWhenCustomDispatcherServletSameNameShouldReturnConfiguredServletPath() {
|
|
||||||
this.contextRunner.withUserConfiguration(CustomDispatcherServletSameName.class)
|
this.contextRunner.withUserConfiguration(CustomDispatcherServletSameName.class)
|
||||||
.withPropertyValues("server.servlet.path:/spring")
|
.withPropertyValues("server.servlet.path:/spring")
|
||||||
.run((context) -> assertThat(context
|
.run((context) -> assertThat(
|
||||||
.getBean(DispatcherServletPathProvider.class).getServletPaths())
|
context.getBean(DispatcherServletPath.class).getPath())
|
||||||
.containsExactly("/spring"));
|
.isEqualTo("/spring"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void pathProviderNotCreatedWhenDefaultDispatcherServletNotAvailable() {
|
public void dispatcherServletPathNotCreatedWhenDefaultDispatcherServletNotAvailable() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withUserConfiguration(CustomDispatcherServletDifferentName.class,
|
.withUserConfiguration(CustomDispatcherServletDifferentName.class,
|
||||||
NonServletConfiguration.class)
|
NonServletConfiguration.class)
|
||||||
.run((context) -> assertThat(context)
|
.run((context) -> assertThat(context)
|
||||||
.doesNotHaveBean(DispatcherServletPathProvider.class));
|
.doesNotHaveBean(DispatcherServletPath.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void pathProviderNotCreatedWhenCustomRegistrationBeanPresent() {
|
public void dispatcherServletPathNotCreatedWhenCustomRegistrationBeanPresent() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withUserConfiguration(CustomDispatcherServletRegistration.class)
|
.withUserConfiguration(CustomDispatcherServletRegistration.class)
|
||||||
.run((context) -> assertThat(context)
|
.run((context) -> assertThat(context)
|
||||||
.doesNotHaveBean(DispatcherServletPathProvider.class));
|
.doesNotHaveBean(DispatcherServletPath.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -237,11 +228,11 @@ public class DispatcherServletAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
protected static class CustomDispatcherServletPathProvider {
|
protected static class CustomDispatcherServletPath {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DispatcherServletPathProvider dispatcherServletPathProvider() {
|
public DispatcherServletPath dispatcherServletPath() {
|
||||||
return mock(DispatcherServletPathProvider.class);
|
return mock(DispatcherServletPath.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -259,8 +250,8 @@ public class DispatcherServletAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DispatcherServletPathProvider dispatcherServletPathProvider() {
|
public DispatcherServletPath dispatcherServletPath() {
|
||||||
return mock(DispatcherServletPathProvider.class);
|
return mock(DispatcherServletPath.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2018 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
|
||||||
|
*
|
||||||
|
* http://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 org.springframework.boot.autoconfigure.web.servlet;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link DispatcherServletPath}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class DispatcherServletPathTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getRelativePathReturnsRelativePath() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring").getRelativePath("boot"))
|
||||||
|
.isEqualTo("spring/boot");
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring/").getRelativePath("boot"))
|
||||||
|
.isEqualTo("spring/boot");
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring").getRelativePath("/boot"))
|
||||||
|
.isEqualTo("spring/boot");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPrefixWhenHasSimplePathReturnPath() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring").getPrefix())
|
||||||
|
.isEqualTo("spring");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPrefixWhenHasPatternRemovesPattern() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring/*.do").getPrefix())
|
||||||
|
.isEqualTo("spring");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPathWhenPathEndsWithSlashRemovesSlash() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring/").getPrefix())
|
||||||
|
.isEqualTo("spring");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getServletUrlMappingWhenPathIsEmptyReturnsSlash() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "").getServletUrlMapping())
|
||||||
|
.isEqualTo("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getServletUrlMappingWhenPathIsSlashReturnsSlash() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "/").getServletUrlMapping())
|
||||||
|
.isEqualTo("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getServletUrlMappingWhenPathContainsStarReturnsPath() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring/*.do").getServletUrlMapping())
|
||||||
|
.isEqualTo("spring/*.do");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getServletUrlMappingWhenHasPathNotEndingSlashReturnsSlashStarPattern() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring/boot").getServletUrlMapping())
|
||||||
|
.isEqualTo("spring/boot/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getServletUrlMappingWhenHasPathEndingWithSlashReturnsSlashStarPattern() {
|
||||||
|
assertThat(((DispatcherServletPath) () -> "spring/boot/").getServletUrlMapping())
|
||||||
|
.isEqualTo("spring/boot/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2018 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
|
||||||
|
*
|
||||||
|
* http://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 org.springframework.boot.autoconfigure.web.servlet;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
import org.springframework.web.servlet.DispatcherServlet;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link DispatcherServletRegistrationBean}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class DispatcherServletRegistrationBeanTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWhenPathIsNullThrowsException() {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("Path must not be null");
|
||||||
|
new DispatcherServletRegistrationBean(new DispatcherServlet(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getPathReturnsPath() {
|
||||||
|
DispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(
|
||||||
|
new DispatcherServlet(), "/test");
|
||||||
|
assertThat(bean.getPath()).isEqualTo("/test");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getUrlMappingsReturnsSinglePathMappedPattern() {
|
||||||
|
DispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(
|
||||||
|
new DispatcherServlet(), "/test");
|
||||||
|
assertThat(bean.getUrlMappings()).containsOnly("/test/*");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setUrlMappingsCannotBeCalled() {
|
||||||
|
DispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(
|
||||||
|
new DispatcherServlet(), "/test");
|
||||||
|
this.thrown.expect(UnsupportedOperationException.class);
|
||||||
|
bean.setUrlMappings(Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addUrlMappingsCannotBeCalled() {
|
||||||
|
DispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(
|
||||||
|
new DispatcherServlet(), "/test");
|
||||||
|
this.thrown.expect(UnsupportedOperationException.class);
|
||||||
|
bean.addUrlMappings("/test");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
|
||||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||||
import org.springframework.boot.test.rule.OutputCapture;
|
import org.springframework.boot.test.rule.OutputCapture;
|
||||||
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||||
|
|
@ -39,7 +40,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
public class ErrorMvcAutoConfigurationTests {
|
public class ErrorMvcAutoConfigurationTests {
|
||||||
|
|
||||||
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ErrorMvcAutoConfiguration.class));
|
.withConfiguration(
|
||||||
|
AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
|
||||||
|
ErrorMvcAutoConfiguration.class));
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public OutputCapture outputCapture = new OutputCapture();
|
public OutputCapture outputCapture = new OutputCapture();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2017 the original author or authors.
|
* Copyright 2012-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -22,6 +22,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||||
|
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
|
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
@ -48,19 +50,28 @@ import org.springframework.web.servlet.DispatcherServlet;
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||||
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
|
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
|
||||||
@EnableConfigurationProperties(WebMvcProperties.class)
|
@EnableConfigurationProperties({ ServerProperties.class, WebMvcProperties.class })
|
||||||
public class MockMvcAutoConfiguration {
|
public class MockMvcAutoConfiguration {
|
||||||
|
|
||||||
private final WebApplicationContext context;
|
private final WebApplicationContext context;
|
||||||
|
|
||||||
|
private final ServerProperties serverProperties;
|
||||||
|
|
||||||
private final WebMvcProperties webMvcProperties;
|
private final WebMvcProperties webMvcProperties;
|
||||||
|
|
||||||
MockMvcAutoConfiguration(WebApplicationContext context,
|
MockMvcAutoConfiguration(WebApplicationContext context,
|
||||||
WebMvcProperties webMvcProperties) {
|
ServerProperties serverProperties, WebMvcProperties webMvcProperties) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.serverProperties = serverProperties;
|
||||||
this.webMvcProperties = webMvcProperties;
|
this.webMvcProperties = webMvcProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public DispatcherServletPath dispatcherServletPath() {
|
||||||
|
return () -> this.serverProperties.getServlet().getPath();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(MockMvcBuilder.class)
|
@ConditionalOnMissingBean(MockMvcBuilder.class)
|
||||||
public DefaultMockMvcBuilder mockMvcBuilder(
|
public DefaultMockMvcBuilder mockMvcBuilder(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue