Skip to content

Commit 72dd3b5

Browse files
committed
Merge branch '2.2.x' into 2.3.x
Closes gh-24747
2 parents 7625a97 + f9e3e0d commit 72dd3b5

File tree

4 files changed

+117
-71
lines changed

4 files changed

+117
-71
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java

Lines changed: 109 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 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,13 +17,14 @@
1717
package org.springframework.boot.autoconfigure.web.servlet;
1818

1919
import java.time.Duration;
20-
import java.util.Arrays;
20+
import java.util.HashSet;
2121
import java.util.List;
2222
import java.util.ListIterator;
2323
import java.util.Map;
24-
import java.util.Optional;
24+
import java.util.Set;
2525

2626
import javax.servlet.Servlet;
27+
import javax.servlet.ServletContext;
2728

2829
import org.apache.commons.logging.Log;
2930
import org.apache.commons.logging.LogFactory;
@@ -73,10 +74,10 @@
7374
import org.springframework.core.task.AsyncTaskExecutor;
7475
import org.springframework.format.FormatterRegistry;
7576
import org.springframework.format.support.FormattingConversionService;
76-
import org.springframework.http.CacheControl;
7777
import org.springframework.http.MediaType;
7878
import org.springframework.http.converter.HttpMessageConverter;
7979
import org.springframework.util.ClassUtils;
80+
import org.springframework.util.PathMatcher;
8081
import org.springframework.validation.DefaultMessageCodesResolver;
8182
import org.springframework.validation.MessageCodesResolver;
8283
import org.springframework.validation.Validator;
@@ -88,11 +89,13 @@
8889
import org.springframework.web.context.request.NativeWebRequest;
8990
import org.springframework.web.context.request.RequestAttributes;
9091
import org.springframework.web.context.request.RequestContextListener;
92+
import org.springframework.web.context.support.ServletContextResource;
9193
import org.springframework.web.filter.FormContentFilter;
9294
import org.springframework.web.filter.HiddenHttpMethodFilter;
9395
import org.springframework.web.filter.RequestContextFilter;
9496
import org.springframework.web.servlet.DispatcherServlet;
9597
import org.springframework.web.servlet.HandlerExceptionResolver;
98+
import org.springframework.web.servlet.HandlerMapping;
9699
import org.springframework.web.servlet.LocaleResolver;
97100
import org.springframework.web.servlet.View;
98101
import org.springframework.web.servlet.ViewResolver;
@@ -107,13 +110,15 @@
107110
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
108111
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
109112
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
113+
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
110114
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
111115
import org.springframework.web.servlet.i18n.FixedLocaleResolver;
112116
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
113117
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
114118
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
115119
import org.springframework.web.servlet.resource.AppCacheManifestTransformer;
116120
import org.springframework.web.servlet.resource.EncodedResourceResolver;
121+
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
117122
import org.springframework.web.servlet.resource.ResourceResolver;
118123
import org.springframework.web.servlet.resource.ResourceUrlProvider;
119124
import org.springframework.web.servlet.resource.VersionResourceResolver;
@@ -155,7 +160,7 @@ public class WebMvcAutoConfiguration {
155160
*/
156161
public static final String DEFAULT_SUFFIX = "";
157162

158-
private static final String[] SERVLET_LOCATIONS = { "/" };
163+
private static final String SERVLET_LOCATION = "/";
159164

160165
@Bean
161166
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@@ -171,13 +176,6 @@ public OrderedFormContentFilter formContentFilter() {
171176
return new OrderedFormContentFilter();
172177
}
173178

174-
static String[] getResourceLocations(String[] staticLocations) {
175-
String[] locations = new String[staticLocations.length + SERVLET_LOCATIONS.length];
176-
System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
177-
System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length, SERVLET_LOCATIONS.length);
178-
return locations;
179-
}
180-
181179
// Defined as a nested config to ensure WebMvcConfigurer is not read when not
182180
// on the classpath
183181
@Configuration(proxyBeanMethods = false)
@@ -186,10 +184,6 @@ static String[] getResourceLocations(String[] staticLocations) {
186184
@Order(0)
187185
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
188186

189-
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
190-
191-
private final ResourceProperties resourceProperties;
192-
193187
private final WebMvcProperties mvcProperties;
194188

195189
private final ListableBeanFactory beanFactory;
@@ -202,12 +196,11 @@ public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
202196

203197
final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
204198

205-
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
206-
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
199+
public WebMvcAutoConfigurationAdapter(WebMvcProperties mvcProperties, ListableBeanFactory beanFactory,
200+
ObjectProvider<HttpMessageConverters> messageConvertersProvider,
207201
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
208202
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
209203
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
210-
this.resourceProperties = resourceProperties;
211204
this.mvcProperties = mvcProperties;
212205
this.beanFactory = beanFactory;
213206
this.messageConvertersProvider = messageConvertersProvider;
@@ -328,37 +321,6 @@ public void addFormatters(FormatterRegistry registry) {
328321
ApplicationConversionService.addBeans(registry, this.beanFactory);
329322
}
330323

331-
@Override
332-
public void addResourceHandlers(ResourceHandlerRegistry registry) {
333-
if (!this.resourceProperties.isAddMappings()) {
334-
logger.debug("Default resource handling disabled");
335-
return;
336-
}
337-
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
338-
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
339-
if (!registry.hasMappingForPattern("/webjars/**")) {
340-
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
341-
.addResourceLocations("classpath:/META-INF/resources/webjars/")
342-
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
343-
}
344-
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
345-
if (!registry.hasMappingForPattern(staticPathPattern)) {
346-
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
347-
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
348-
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
349-
}
350-
}
351-
352-
private Integer getSeconds(Duration cachePeriod) {
353-
return (cachePeriod != null) ? (int) cachePeriod.getSeconds() : null;
354-
}
355-
356-
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
357-
if (this.resourceHandlerRegistrationCustomizer != null) {
358-
this.resourceHandlerRegistrationCustomizer.customize(registration);
359-
}
360-
}
361-
362324
@Bean
363325
@ConditionalOnMissingBean({ RequestContextListener.class, RequestContextFilter.class })
364326
@ConditionalOnMissingFilterBean(RequestContextFilter.class)
@@ -374,22 +336,31 @@ public static RequestContextFilter requestContextFilter() {
374336
@Configuration(proxyBeanMethods = false)
375337
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
376338

339+
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
340+
377341
private final ResourceProperties resourceProperties;
378342

379343
private final WebMvcProperties mvcProperties;
380344

381-
private final ListableBeanFactory beanFactory;
382-
383345
private final WebMvcRegistrations mvcRegistrations;
384346

347+
private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
348+
385349
private ResourceLoader resourceLoader;
386350

351+
private final ListableBeanFactory beanFactory;
352+
353+
private final Set<String> autoConfiguredResourceHandlers = new HashSet<>();
354+
387355
public EnableWebMvcConfiguration(ResourceProperties resourceProperties,
388356
ObjectProvider<WebMvcProperties> mvcPropertiesProvider,
389-
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
357+
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,
358+
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
359+
ListableBeanFactory beanFactory) {
390360
this.resourceProperties = resourceProperties;
391361
this.mvcProperties = mvcPropertiesProvider.getIfAvailable();
392362
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
363+
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
393364
this.beanFactory = beanFactory;
394365
}
395366

@@ -429,6 +400,72 @@ public RequestMappingHandlerMapping requestMappingHandlerMapping(
429400
resourceUrlProvider);
430401
}
431402

403+
@Bean
404+
@Override
405+
public HandlerMapping resourceHandlerMapping(UrlPathHelper urlPathHelper, PathMatcher pathMatcher,
406+
ContentNegotiationManager contentNegotiationManager, FormattingConversionService conversionService,
407+
ResourceUrlProvider resourceUrlProvider) {
408+
HandlerMapping mapping = super.resourceHandlerMapping(urlPathHelper, pathMatcher, contentNegotiationManager,
409+
conversionService, resourceUrlProvider);
410+
if (mapping instanceof SimpleUrlHandlerMapping) {
411+
addServletContextResourceHandlerMapping((SimpleUrlHandlerMapping) mapping);
412+
}
413+
return mapping;
414+
}
415+
416+
private void addServletContextResourceHandlerMapping(SimpleUrlHandlerMapping mapping) {
417+
Map<String, ?> urlMap = mapping.getUrlMap();
418+
String pattern = this.mvcProperties.getStaticPathPattern();
419+
Object handler = urlMap.get(pattern);
420+
if (handler instanceof ResourceHttpRequestHandler
421+
&& this.autoConfiguredResourceHandlers.contains(pattern)) {
422+
addServletContextResourceHandlerMapping((ResourceHttpRequestHandler) handler);
423+
}
424+
}
425+
426+
private void addServletContextResourceHandlerMapping(ResourceHttpRequestHandler handler) {
427+
ServletContext servletContext = getServletContext();
428+
if (servletContext != null) {
429+
List<Resource> locations = handler.getLocations();
430+
locations.add(new ServletContextResource(servletContext, SERVLET_LOCATION));
431+
}
432+
}
433+
434+
@Override
435+
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
436+
super.addResourceHandlers(registry);
437+
if (!this.resourceProperties.isAddMappings()) {
438+
logger.debug("Default resource handling disabled");
439+
return;
440+
}
441+
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
442+
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(),
443+
this.resourceProperties.getStaticLocations());
444+
445+
}
446+
447+
private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {
448+
if (registry.hasMappingForPattern(pattern)) {
449+
return;
450+
}
451+
ResourceHandlerRegistration registration = registry.addResourceHandler(pattern);
452+
registration.addResourceLocations(locations);
453+
registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));
454+
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
455+
customizeResourceHandlerRegistration(registration);
456+
this.autoConfiguredResourceHandlers.add(pattern);
457+
}
458+
459+
private Integer getSeconds(Duration cachePeriod) {
460+
return (cachePeriod != null) ? (int) cachePeriod.getSeconds() : null;
461+
}
462+
463+
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
464+
if (this.resourceHandlerRegistrationCustomizer != null) {
465+
this.resourceHandlerRegistrationCustomizer.customize(registration);
466+
}
467+
}
468+
432469
@Bean
433470
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
434471
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
@@ -440,22 +477,34 @@ public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext ap
440477
return welcomePageHandlerMapping;
441478
}
442479

443-
private Optional<Resource> getWelcomePage() {
444-
String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
445-
return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
480+
private Resource getWelcomePage() {
481+
for (String location : this.resourceProperties.getStaticLocations()) {
482+
Resource indexHtml = getIndexHtml(location);
483+
if (indexHtml != null) {
484+
return indexHtml;
485+
}
486+
}
487+
ServletContext servletContext = getServletContext();
488+
if (servletContext != null) {
489+
return getIndexHtml(new ServletContextResource(servletContext, SERVLET_LOCATION));
490+
}
491+
return null;
446492
}
447493

448494
private Resource getIndexHtml(String location) {
449-
return this.resourceLoader.getResource(location + "index.html");
495+
return getIndexHtml(this.resourceLoader.getResource(location));
450496
}
451497

452-
private boolean isReadable(Resource resource) {
498+
private Resource getIndexHtml(Resource location) {
453499
try {
454-
return resource.exists() && (resource.getURL() != null);
500+
Resource resource = location.createRelative("index.html");
501+
if (resource.exists() && (resource.getURL() != null)) {
502+
return resource;
503+
}
455504
}
456505
catch (Exception ex) {
457-
return false;
458506
}
507+
return null;
459508
}
460509

461510
@Bean

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WelcomePageHandlerMapping.java

Lines changed: 4 additions & 5 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-2021 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.
@@ -18,7 +18,6 @@
1818

1919
import java.util.Collections;
2020
import java.util.List;
21-
import java.util.Optional;
2221

2322
import javax.servlet.http.HttpServletRequest;
2423

@@ -49,9 +48,9 @@ final class WelcomePageHandlerMapping extends AbstractUrlHandlerMapping {
4948
private static final List<MediaType> MEDIA_TYPES_ALL = Collections.singletonList(MediaType.ALL);
5049

5150
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,
52-
ApplicationContext applicationContext, Optional<Resource> welcomePage, String staticPathPattern) {
53-
if (welcomePage.isPresent() && "/**".equals(staticPathPattern)) {
54-
logger.info("Adding welcome page: " + welcomePage.get());
51+
ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) {
52+
if (welcomePage != null && "/**".equals(staticPathPattern)) {
53+
logger.info("Adding welcome page: " + welcomePage);
5554
setRootViewName("forward:index.html");
5655
}
5756
else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 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.
@@ -913,7 +913,7 @@ private void assertCacheControl(AssertableWebApplicationContext context) {
913913
protected Map<String, List<Resource>> getResourceMappingLocations(ApplicationContext context) {
914914
Object bean = context.getBean("resourceHandlerMapping");
915915
if (bean instanceof HandlerMapping) {
916-
return getMappingLocations(context.getBean("resourceHandlerMapping", HandlerMapping.class));
916+
return getMappingLocations((HandlerMapping) bean);
917917
}
918918
assertThat(bean.toString()).isEqualTo("null");
919919
return Collections.emptyMap();

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WelcomePageHandlerMappingTests.java

Lines changed: 2 additions & 4 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-2021 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.
@@ -18,7 +18,6 @@
1818

1919
import java.util.Collections;
2020
import java.util.Map;
21-
import java.util.Optional;
2221

2322
import javax.servlet.http.HttpServletRequest;
2423
import javax.servlet.http.HttpServletResponse;
@@ -162,8 +161,7 @@ WelcomePageHandlerMapping handlerMapping(ApplicationContext applicationContext,
162161
return new WelcomePageHandlerMapping(
163162
templateAvailabilityProviders
164163
.getIfAvailable(() -> new TemplateAvailabilityProviders(applicationContext)),
165-
applicationContext, Optional.ofNullable(staticIndexPage.getIfAvailable()), staticPathPattern);
166-
164+
applicationContext, staticIndexPage.getIfAvailable(), staticPathPattern);
167165
}
168166

169167
}

0 commit comments

Comments
 (0)