Skip to content

Commit f1fcfa6

Browse files
committed
Merge branch '2.3.x' into 2.4.x
Closes gh-24748
2 parents 53a6fa2 + 72dd3b5 commit f1fcfa6

File tree

4 files changed

+111
-72
lines changed

4 files changed

+111
-72
lines changed

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

+104-62
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@
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.Locale;
2424
import java.util.Map;
25-
import java.util.Optional;
25+
import java.util.Set;
2626

2727
import javax.servlet.Servlet;
28+
import javax.servlet.ServletContext;
2829

2930
import org.apache.commons.logging.Log;
3031
import org.apache.commons.logging.LogFactory;
@@ -74,7 +75,6 @@
7475
import org.springframework.core.task.AsyncTaskExecutor;
7576
import org.springframework.format.FormatterRegistry;
7677
import org.springframework.format.support.FormattingConversionService;
77-
import org.springframework.http.CacheControl;
7878
import org.springframework.http.MediaType;
7979
import org.springframework.http.converter.HttpMessageConverter;
8080
import org.springframework.util.ClassUtils;
@@ -88,12 +88,14 @@
8888
import org.springframework.web.context.request.NativeWebRequest;
8989
import org.springframework.web.context.request.RequestAttributes;
9090
import org.springframework.web.context.request.RequestContextListener;
91+
import org.springframework.web.context.support.ServletContextResource;
9192
import org.springframework.web.filter.FormContentFilter;
9293
import org.springframework.web.filter.HiddenHttpMethodFilter;
9394
import org.springframework.web.filter.RequestContextFilter;
9495
import org.springframework.web.servlet.DispatcherServlet;
9596
import org.springframework.web.servlet.FlashMapManager;
9697
import org.springframework.web.servlet.HandlerExceptionResolver;
98+
import org.springframework.web.servlet.HandlerMapping;
9799
import org.springframework.web.servlet.LocaleResolver;
98100
import org.springframework.web.servlet.ThemeResolver;
99101
import org.springframework.web.servlet.View;
@@ -109,12 +111,14 @@
109111
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
110112
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
111113
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
114+
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
112115
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
113116
import org.springframework.web.servlet.i18n.FixedLocaleResolver;
114117
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
115118
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
116119
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
117120
import org.springframework.web.servlet.resource.EncodedResourceResolver;
121+
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
118122
import org.springframework.web.servlet.resource.ResourceResolver;
119123
import org.springframework.web.servlet.resource.ResourceUrlProvider;
120124
import org.springframework.web.servlet.resource.VersionResourceResolver;
@@ -158,7 +162,7 @@ public class WebMvcAutoConfiguration {
158162
*/
159163
public static final String DEFAULT_SUFFIX = "";
160164

161-
private static final String[] SERVLET_LOCATIONS = { "/" };
165+
private static final String SERVLET_LOCATION = "/";
162166

163167
@Bean
164168
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@@ -174,13 +178,6 @@ public OrderedFormContentFilter formContentFilter() {
174178
return new OrderedFormContentFilter();
175179
}
176180

177-
static String[] getResourceLocations(String[] staticLocations) {
178-
String[] locations = new String[staticLocations.length + SERVLET_LOCATIONS.length];
179-
System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);
180-
System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length, SERVLET_LOCATIONS.length);
181-
return locations;
182-
}
183-
184181
// Defined as a nested config to ensure WebMvcConfigurer is not read when not
185182
// on the classpath
186183
@SuppressWarnings("deprecation")
@@ -191,10 +188,6 @@ static String[] getResourceLocations(String[] staticLocations) {
191188
@Order(0)
192189
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
193190

194-
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
195-
196-
private final Resources resourceProperties;
197-
198191
private final WebMvcProperties mvcProperties;
199192

200193
private final ListableBeanFactory beanFactory;
@@ -207,15 +200,11 @@ public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
207200

208201
final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
209202

210-
public WebMvcAutoConfigurationAdapter(
211-
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
212-
WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory,
213-
ObjectProvider<HttpMessageConverters> messageConvertersProvider,
203+
public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties,
204+
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
214205
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
215206
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
216207
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
217-
this.resourceProperties = resourceProperties.hasBeenCustomized() ? resourceProperties
218-
: webProperties.getResources();
219208
this.mvcProperties = mvcProperties;
220209
this.beanFactory = beanFactory;
221210
this.messageConvertersProvider = messageConvertersProvider;
@@ -327,39 +316,6 @@ public void addFormatters(FormatterRegistry registry) {
327316
ApplicationConversionService.addBeans(registry, this.beanFactory);
328317
}
329318

330-
@Override
331-
public void addResourceHandlers(ResourceHandlerRegistry registry) {
332-
if (!this.resourceProperties.isAddMappings()) {
333-
logger.debug("Default resource handling disabled");
334-
return;
335-
}
336-
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
337-
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
338-
if (!registry.hasMappingForPattern("/webjars/**")) {
339-
customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
340-
.addResourceLocations("classpath:/META-INF/resources/webjars/")
341-
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)
342-
.setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
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-
.setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
350-
}
351-
}
352-
353-
private Integer getSeconds(Duration cachePeriod) {
354-
return (cachePeriod != null) ? (int) cachePeriod.getSeconds() : null;
355-
}
356-
357-
private void customizeResourceHandlerRegistration(ResourceHandlerRegistration registration) {
358-
if (this.resourceHandlerRegistrationCustomizer != null) {
359-
this.resourceHandlerRegistrationCustomizer.customize(registration);
360-
}
361-
}
362-
363319
@Bean
364320
@ConditionalOnMissingBean({ RequestContextListener.class, RequestContextFilter.class })
365321
@ConditionalOnMissingFilterBean(RequestContextFilter.class)
@@ -376,6 +332,8 @@ public static RequestContextFilter requestContextFilter() {
376332
@EnableConfigurationProperties(WebProperties.class)
377333
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
378334

335+
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
336+
379337
private final Resources resourceProperties;
380338

381339
private final WebMvcProperties mvcProperties;
@@ -386,18 +344,25 @@ public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfigurat
386344

387345
private final WebMvcRegistrations mvcRegistrations;
388346

347+
private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
348+
389349
private ResourceLoader resourceLoader;
390350

351+
private final Set<String> autoConfiguredResourceHandlers = new HashSet<>();
352+
391353
@SuppressWarnings("deprecation")
392354
public EnableWebMvcConfiguration(
393355
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
394356
WebMvcProperties mvcProperties, WebProperties webProperties,
395-
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
357+
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,
358+
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
359+
ListableBeanFactory beanFactory) {
396360
this.resourceProperties = resourceProperties.hasBeenCustomized() ? resourceProperties
397361
: webProperties.getResources();
398362
this.mvcProperties = mvcProperties;
399363
this.webProperties = webProperties;
400364
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
365+
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
401366
this.beanFactory = beanFactory;
402367
}
403368

@@ -437,6 +402,71 @@ public RequestMappingHandlerMapping requestMappingHandlerMapping(
437402
resourceUrlProvider);
438403
}
439404

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

483-
private Optional<Resource> getWelcomePage() {
484-
String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
485-
return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
513+
private Resource getWelcomePage() {
514+
for (String location : this.resourceProperties.getStaticLocations()) {
515+
Resource indexHtml = getIndexHtml(location);
516+
if (indexHtml != null) {
517+
return indexHtml;
518+
}
519+
}
520+
ServletContext servletContext = getServletContext();
521+
if (servletContext != null) {
522+
return getIndexHtml(new ServletContextResource(servletContext, SERVLET_LOCATION));
523+
}
524+
return null;
486525
}
487526

488527
private Resource getIndexHtml(String location) {
489-
return this.resourceLoader.getResource(location + "index.html");
528+
return getIndexHtml(this.resourceLoader.getResource(location));
490529
}
491530

492-
private boolean isReadable(Resource resource) {
531+
private Resource getIndexHtml(Resource location) {
493532
try {
494-
return resource.exists() && (resource.getURL() != null);
533+
Resource resource = location.createRelative("index.html");
534+
if (resource.exists() && (resource.getURL() != null)) {
535+
return resource;
536+
}
495537
}
496538
catch (Exception ex) {
497-
return false;
498539
}
540+
return null;
499541
}
500542

501543
@Bean

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

+4-5
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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ private void assertResourceHttpRequestHandler(AssertableWebApplicationContext co
10191019
protected Map<String, List<Resource>> getResourceMappingLocations(ApplicationContext context) {
10201020
Object bean = context.getBean("resourceHandlerMapping");
10211021
if (bean instanceof HandlerMapping) {
1022-
return getMappingLocations(context.getBean("resourceHandlerMapping", HandlerMapping.class));
1022+
return getMappingLocations((HandlerMapping) bean);
10231023
}
10241024
assertThat(bean.toString()).isEqualTo("null");
10251025
return Collections.emptyMap();

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

+2-4
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)