1717package org .springframework .boot .autoconfigure .web .servlet ;
1818
1919import java .time .Duration ;
20- import java .util .HashSet ;
20+ import java .util .LinkedHashMap ;
2121import java .util .List ;
2222import java .util .ListIterator ;
2323import java .util .Map ;
24- import java .util .Set ;
2524
2625import javax .servlet .Servlet ;
2726import javax .servlet .ServletContext ;
5453import org .springframework .boot .autoconfigure .web .ResourceProperties .Strategy ;
5554import org .springframework .boot .autoconfigure .web .format .DateTimeFormatters ;
5655import org .springframework .boot .autoconfigure .web .format .WebConversionService ;
56+ import org .springframework .boot .autoconfigure .web .servlet .WebMvcAutoConfiguration .AutoConfigurationResourceHandlerRegistry .RegistrationType ;
5757import org .springframework .boot .autoconfigure .web .servlet .WebMvcProperties .Format ;
5858import org .springframework .boot .context .properties .EnableConfigurationProperties ;
5959import org .springframework .boot .convert .ApplicationConversionService ;
7676import org .springframework .format .support .FormattingConversionService ;
7777import org .springframework .http .MediaType ;
7878import org .springframework .http .converter .HttpMessageConverter ;
79+ import org .springframework .util .Assert ;
7980import org .springframework .util .ClassUtils ;
8081import org .springframework .util .PathMatcher ;
8182import org .springframework .validation .DefaultMessageCodesResolver ;
110111import org .springframework .web .servlet .config .annotation .WebMvcConfigurationSupport ;
111112import org .springframework .web .servlet .config .annotation .WebMvcConfigurer ;
112113import org .springframework .web .servlet .handler .AbstractHandlerExceptionResolver ;
114+ import org .springframework .web .servlet .handler .AbstractHandlerMapping ;
113115import org .springframework .web .servlet .handler .SimpleUrlHandlerMapping ;
114116import org .springframework .web .servlet .i18n .AcceptHeaderLocaleResolver ;
115117import org .springframework .web .servlet .i18n .FixedLocaleResolver ;
@@ -184,6 +186,10 @@ public OrderedFormContentFilter formContentFilter() {
184186 @ Order (0 )
185187 public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
186188
189+ private static final Log logger = LogFactory .getLog (WebMvcConfigurer .class );
190+
191+ private final ResourceProperties resourceProperties ;
192+
187193 private final WebMvcProperties mvcProperties ;
188194
189195 private final ListableBeanFactory beanFactory ;
@@ -194,13 +200,14 @@ public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
194200
195201 private final ObjectProvider <ServletRegistrationBean <?>> servletRegistrations ;
196202
197- final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer ;
203+ private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer ;
198204
199- public WebMvcAutoConfigurationAdapter (WebMvcProperties mvcProperties , ListableBeanFactory beanFactory ,
200- ObjectProvider <HttpMessageConverters > messageConvertersProvider ,
205+ public WebMvcAutoConfigurationAdapter (ResourceProperties resourceProperties , WebMvcProperties mvcProperties ,
206+ ListableBeanFactory beanFactory , ObjectProvider <HttpMessageConverters > messageConvertersProvider ,
201207 ObjectProvider <ResourceHandlerRegistrationCustomizer > resourceHandlerRegistrationCustomizerProvider ,
202208 ObjectProvider <DispatcherServletPath > dispatcherServletPath ,
203209 ObjectProvider <ServletRegistrationBean <?>> servletRegistrations ) {
210+ this .resourceProperties = resourceProperties ;
204211 this .mvcProperties = mvcProperties ;
205212 this .beanFactory = beanFactory ;
206213 this .messageConvertersProvider = messageConvertersProvider ;
@@ -321,6 +328,39 @@ public void addFormatters(FormatterRegistry registry) {
321328 ApplicationConversionService .addBeans (registry , this .beanFactory );
322329 }
323330
331+ @ Override
332+ public void addResourceHandlers (ResourceHandlerRegistry registry ) {
333+ if (!this .resourceProperties .isAddMappings ()) {
334+ logger .debug ("Default resource handling disabled" );
335+ return ;
336+ }
337+ addResourceHandler (registry , "/webjars/**" , "classpath:/META-INF/resources/webjars/" );
338+ addResourceHandler (registry , this .mvcProperties .getStaticPathPattern (),
339+ this .resourceProperties .getStaticLocations ());
340+ }
341+
342+ private void addResourceHandler (ResourceHandlerRegistry registry , String pattern , String ... locations ) {
343+ if (registry .hasMappingForPattern (pattern )) {
344+ return ;
345+ }
346+ ResourceHandlerRegistration registration = AutoConfigurationResourceHandlerRegistry
347+ .addResourceHandler (registry , RegistrationType .AUTO_CONFIGURATION , pattern );
348+ registration .addResourceLocations (locations );
349+ registration .setCachePeriod (getSeconds (this .resourceProperties .getCache ().getPeriod ()));
350+ registration .setCacheControl (this .resourceProperties .getCache ().getCachecontrol ().toHttpCacheControl ());
351+ customizeResourceHandlerRegistration (registration );
352+ }
353+
354+ private Integer getSeconds (Duration cachePeriod ) {
355+ return (cachePeriod != null ) ? (int ) cachePeriod .getSeconds () : null ;
356+ }
357+
358+ private void customizeResourceHandlerRegistration (ResourceHandlerRegistration registration ) {
359+ if (this .resourceHandlerRegistrationCustomizer != null ) {
360+ this .resourceHandlerRegistrationCustomizer .customize (registration );
361+ }
362+ }
363+
324364 @ Bean
325365 @ ConditionalOnMissingBean ({ RequestContextListener .class , RequestContextFilter .class })
326366 @ ConditionalOnMissingFilterBean (RequestContextFilter .class )
@@ -336,31 +376,22 @@ public static RequestContextFilter requestContextFilter() {
336376 @ Configuration (proxyBeanMethods = false )
337377 public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
338378
339- private static final Log logger = LogFactory .getLog (WebMvcConfigurer .class );
340-
341379 private final ResourceProperties resourceProperties ;
342380
343381 private final WebMvcProperties mvcProperties ;
344382
345383 private final WebMvcRegistrations mvcRegistrations ;
346384
347- private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer ;
348-
349385 private ResourceLoader resourceLoader ;
350386
351387 private final ListableBeanFactory beanFactory ;
352388
353- private final Set <String > autoConfiguredResourceHandlers = new HashSet <>();
354-
355389 public EnableWebMvcConfiguration (ResourceProperties resourceProperties ,
356390 ObjectProvider <WebMvcProperties > mvcPropertiesProvider ,
357- ObjectProvider <WebMvcRegistrations > mvcRegistrationsProvider ,
358- ObjectProvider <ResourceHandlerRegistrationCustomizer > resourceHandlerRegistrationCustomizerProvider ,
359- ListableBeanFactory beanFactory ) {
391+ ObjectProvider <WebMvcRegistrations > mvcRegistrationsProvider , ListableBeanFactory beanFactory ) {
360392 this .resourceProperties = resourceProperties ;
361393 this .mvcProperties = mvcPropertiesProvider .getIfAvailable ();
362394 this .mvcRegistrations = mvcRegistrationsProvider .getIfUnique ();
363- this .resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider .getIfAvailable ();
364395 this .beanFactory = beanFactory ;
365396 }
366397
@@ -402,70 +433,28 @@ public RequestMappingHandlerMapping requestMappingHandlerMapping(
402433
403434 @ Bean
404435 @ 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 );
436+ public HandlerMapping resourceHandlerMapping (@ Qualifier ("mvcUrlPathHelper" ) UrlPathHelper urlPathHelper ,
437+ @ Qualifier ("mvcPathMatcher" ) PathMatcher pathMatcher ,
438+ @ Qualifier ("mvcContentNegotiationManager" ) ContentNegotiationManager contentNegotiationManager ,
439+ @ Qualifier ("mvcConversionService" ) FormattingConversionService conversionService ,
440+ @ Qualifier ("mvcResourceUrlProvider" ) ResourceUrlProvider resourceUrlProvider ) {
441+ Assert .state (getApplicationContext () != null , "No ApplicationContext set" );
442+ Assert .state (getServletContext () != null , "No ServletContext set" );
443+ AutoConfigurationResourceHandlerRegistry registry = new AutoConfigurationResourceHandlerRegistry (
444+ getApplicationContext (), getServletContext (), contentNegotiationManager , urlPathHelper ,
445+ this .mvcProperties );
446+ addResourceHandlers (registry );
447+ AbstractHandlerMapping mapping = registry .getHandlerMapping ();
448+ if (mapping == null ) {
449+ return null ;
412450 }
451+ mapping .setPathMatcher (pathMatcher );
452+ mapping .setUrlPathHelper (urlPathHelper );
453+ mapping .setInterceptors (getInterceptors (conversionService , resourceUrlProvider ));
454+ mapping .setCorsConfigurations (getCorsConfigurations ());
413455 return mapping ;
414456 }
415457
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-
469458 @ Bean
470459 public WelcomePageHandlerMapping welcomePageHandlerMapping (ApplicationContext applicationContext ,
471460 FormattingConversionService mvcConversionService , ResourceUrlProvider mvcResourceUrlProvider ) {
@@ -677,4 +666,84 @@ public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest)
677666
678667 }
679668
669+ /**
670+ * {@link ResourceHandlerRegistry} that tracks auto-configuration and when appropriate
671+ * adds the {@link ServletContextResource} for {@code /}.
672+ */
673+ static class AutoConfigurationResourceHandlerRegistry
674+ extends org .springframework .web .servlet .config .annotation .ResourceHandlerRegistry {
675+
676+ private final ServletContext servletContext ;
677+
678+ private final WebMvcProperties mvcProperties ;
679+
680+ private final Map <String , RegistrationType > registrations = new LinkedHashMap <>();
681+
682+ AutoConfigurationResourceHandlerRegistry (ApplicationContext applicationContext , ServletContext servletContext ,
683+ ContentNegotiationManager contentNegotiationManager , UrlPathHelper pathHelper ,
684+ WebMvcProperties mvcProperties ) {
685+ super (applicationContext , servletContext , contentNegotiationManager , pathHelper );
686+ this .servletContext = servletContext ;
687+ this .mvcProperties = mvcProperties ;
688+ }
689+
690+ @ Override
691+ public ResourceHandlerRegistration addResourceHandler (String ... pathPatterns ) {
692+ return addResourceHandler (RegistrationType .STANDARD , pathPatterns );
693+ }
694+
695+ ResourceHandlerRegistration addResourceHandler (RegistrationType type , String ... pathPatterns ) {
696+ for (String pathPattern : pathPatterns ) {
697+ this .registrations .put (pathPattern , type );
698+ }
699+ return super .addResourceHandler (pathPatterns );
700+ }
701+
702+ @ Override
703+ protected AbstractHandlerMapping getHandlerMapping () {
704+ SimpleUrlHandlerMapping mapping = (SimpleUrlHandlerMapping ) super .getHandlerMapping ();
705+ reconfigure (mapping );
706+ return mapping ;
707+ }
708+
709+ private void reconfigure (SimpleUrlHandlerMapping mapping ) {
710+ String staticPathPattern = this .mvcProperties .getStaticPathPattern ();
711+ if (this .registrations .get (staticPathPattern ) == RegistrationType .AUTO_CONFIGURATION ) {
712+ addServletContextResourceHandlerMapping (mapping , staticPathPattern );
713+ }
714+ }
715+
716+ private void addServletContextResourceHandlerMapping (SimpleUrlHandlerMapping mapping ,
717+ String staticPathPattern ) {
718+ Object handler = mapping .getUrlMap ().get (staticPathPattern );
719+ if (handler instanceof ResourceHttpRequestHandler ) {
720+ addServletContextResourceHandlerMapping ((ResourceHttpRequestHandler ) handler );
721+ }
722+ }
723+
724+ private void addServletContextResourceHandlerMapping (ResourceHttpRequestHandler handler ) {
725+ if (this .servletContext != null ) {
726+ List <Resource > locations = handler .getLocations ();
727+ locations .add (new ServletContextResource (this .servletContext , SERVLET_LOCATION ));
728+ }
729+ }
730+
731+ static ResourceHandlerRegistration addResourceHandler (ResourceHandlerRegistry registry , RegistrationType type ,
732+ String ... pathPatterns ) {
733+ if (registry instanceof AutoConfigurationResourceHandlerRegistry ) {
734+ return ((AutoConfigurationResourceHandlerRegistry ) registry ).addResourceHandler (type , pathPatterns );
735+ }
736+ return registry .addResourceHandler (pathPatterns );
737+ }
738+
739+ enum RegistrationType {
740+
741+ STANDARD ,
742+
743+ AUTO_CONFIGURATION
744+
745+ }
746+
747+ }
748+
680749}
0 commit comments