Commit c22e6558 authored by Andy Wilkinson's avatar Andy Wilkinson

Move spring.resources.* properties to spring.web.resources.*

Closes gh-23917
parent 929d8fcd
......@@ -19,9 +19,13 @@ package org.springframework.boot.autoconfigure.web;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources.Chain;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.util.ClassUtils;
......@@ -41,10 +45,11 @@ class OnEnabledResourceChainCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();
boolean fixed = getEnabledProperty(environment, "strategy.fixed.", false);
boolean content = getEnabledProperty(environment, "strategy.content.", false);
Boolean chain = getEnabledProperty(environment, "", null);
Boolean match = ResourceProperties.Chain.getEnabled(fixed, content, chain);
String prefix = determineResourcePropertiesPrefix(environment);
boolean fixed = getEnabledProperty(environment, prefix, "strategy.fixed.", false);
boolean content = getEnabledProperty(environment, prefix, "strategy.content.", false);
Boolean chain = getEnabledProperty(environment, prefix, "", null);
Boolean match = Chain.getEnabled(fixed, content, chain);
ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnEnabledResourceChain.class);
if (match == null) {
if (ClassUtils.isPresent(WEBJAR_ASSET_LOCATOR, getClass().getClassLoader())) {
......@@ -58,8 +63,19 @@ class OnEnabledResourceChainCondition extends SpringBootCondition {
return ConditionOutcome.noMatch(message.because("disabled"));
}
private Boolean getEnabledProperty(ConfigurableEnvironment environment, String key, Boolean defaultValue) {
String name = "spring.resources.chain." + key + "enabled";
@SuppressWarnings("deprecation")
private String determineResourcePropertiesPrefix(Environment environment) {
BindResult<org.springframework.boot.autoconfigure.web.ResourceProperties> result = Binder.get(environment)
.bind("spring.resources", org.springframework.boot.autoconfigure.web.ResourceProperties.class);
if (result.isBound() && result.get().hasBeenCustomized()) {
return "spring.resources.chain.";
}
return "spring.web.resources.chain.";
}
private Boolean getEnabledProperty(ConfigurableEnvironment environment, String prefix, String key,
Boolean defaultValue) {
String name = prefix + key + "enabled";
return environment.getProperty(name, Boolean.class, defaultValue);
}
......
......@@ -16,8 +16,7 @@
package org.springframework.boot.autoconfigure.web.reactive;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.web.reactive.config.ResourceChainRegistration;
import org.springframework.web.reactive.config.ResourceHandlerRegistration;
import org.springframework.web.reactive.resource.EncodedResourceResolver;
......@@ -32,30 +31,35 @@ import org.springframework.web.reactive.resource.VersionResourceResolver;
*/
class ResourceChainResourceHandlerRegistrationCustomizer implements ResourceHandlerRegistrationCustomizer {
@Autowired
private ResourceProperties resourceProperties = new ResourceProperties();
private final Resources resourceProperties;
ResourceChainResourceHandlerRegistrationCustomizer(Resources resources) {
this.resourceProperties = resources;
}
@Override
public void customize(ResourceHandlerRegistration registration) {
ResourceProperties.Chain properties = this.resourceProperties.getChain();
Resources.Chain properties = this.resourceProperties.getChain();
configureResourceChain(properties, registration.resourceChain(properties.isCache()));
}
@SuppressWarnings("deprecation")
private void configureResourceChain(ResourceProperties.Chain properties, ResourceChainRegistration chain) {
ResourceProperties.Strategy strategy = properties.getStrategy();
private void configureResourceChain(Resources.Chain properties, ResourceChainRegistration chain) {
Resources.Chain.Strategy strategy = properties.getStrategy();
if (properties.isCompressed()) {
chain.addResolver(new EncodedResourceResolver());
}
if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {
chain.addResolver(getVersionResourceResolver(strategy));
}
if (properties.isHtmlApplicationCache()) {
if ((properties instanceof org.springframework.boot.autoconfigure.web.ResourceProperties.Chain)
&& ((org.springframework.boot.autoconfigure.web.ResourceProperties.Chain) properties)
.isHtmlApplicationCache()) {
chain.addTransformer(new org.springframework.web.reactive.resource.AppCacheManifestTransformer());
}
}
private ResourceResolver getVersionResourceResolver(ResourceProperties.Strategy properties) {
private ResourceResolver getVersionResourceResolver(Resources.Chain.Strategy properties) {
VersionResourceResolver resolver = new VersionResourceResolver();
if (properties.getFixed().isEnabled()) {
String version = properties.getFixed().getVersion();
......
......@@ -35,8 +35,8 @@ import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvi
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidatorAdapter;
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.autoconfigure.web.format.DateTimeFormatters;
import org.springframework.boot.autoconfigure.web.format.WebConversionService;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxProperties.Format;
......@@ -106,11 +106,16 @@ public class WebFluxAutoConfiguration {
public static class WelcomePageConfiguration {
@Bean
@SuppressWarnings("deprecation")
public RouterFunctionMapping welcomePageRouterFunctionMapping(ApplicationContext applicationContext,
WebFluxProperties webFluxProperties, ResourceProperties resourceProperties) {
WebFluxProperties webFluxProperties,
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
WebProperties webProperties) {
String[] staticLocations = resourceProperties.hasBeenCustomized() ? resourceProperties.getStaticLocations()
: webProperties.getResources().getStaticLocations();
WelcomePageRouterFunctionFactory factory = new WelcomePageRouterFunctionFactory(
new TemplateAvailabilityProviders(applicationContext), applicationContext,
resourceProperties.getStaticLocations(), webFluxProperties.getStaticPathPattern());
new TemplateAvailabilityProviders(applicationContext), applicationContext, staticLocations,
webFluxProperties.getStaticPathPattern());
RouterFunction<ServerResponse> routerFunction = factory.createRouterFunction();
if (routerFunction != null) {
RouterFunctionMapping routerFunctionMapping = new RouterFunctionMapping(routerFunction);
......@@ -122,14 +127,16 @@ public class WebFluxAutoConfiguration {
}
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ ResourceProperties.class, WebFluxProperties.class })
@EnableConfigurationProperties({ org.springframework.boot.autoconfigure.web.ResourceProperties.class,
WebProperties.class, WebFluxProperties.class })
@Import({ EnableWebFluxConfiguration.class })
public static class WebFluxConfig implements WebFluxConfigurer {
private static final Log logger = LogFactory.getLog(WebFluxConfig.class);
private final ResourceProperties resourceProperties;
private final Resources resourceProperties;
private final WebFluxProperties webFluxProperties;
......@@ -143,12 +150,14 @@ public class WebFluxAutoConfiguration {
private final ObjectProvider<ViewResolver> viewResolvers;
public WebFluxConfig(ResourceProperties resourceProperties, WebFluxProperties webFluxProperties,
ListableBeanFactory beanFactory, ObjectProvider<HandlerMethodArgumentResolver> resolvers,
public WebFluxConfig(org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
WebProperties webProperties, WebFluxProperties webFluxProperties, ListableBeanFactory beanFactory,
ObjectProvider<HandlerMethodArgumentResolver> resolvers,
ObjectProvider<CodecCustomizer> codecCustomizers,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizer,
ObjectProvider<ViewResolver> viewResolvers) {
this.resourceProperties = resourceProperties;
this.resourceProperties = resourceProperties.hasBeenCustomized() ? resourceProperties
: webProperties.getResources();
this.webFluxProperties = webFluxProperties;
this.beanFactory = beanFactory;
this.argumentResolvers = resolvers;
......@@ -190,7 +199,8 @@ public class WebFluxAutoConfiguration {
private void configureResourceCaching(ResourceHandlerRegistration registration) {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
ResourceProperties.Cache.Cachecontrol cacheControl = this.resourceProperties.getCache().getCachecontrol();
WebProperties.Resources.Cache.Cachecontrol cacheControl = this.resourceProperties.getCache()
.getCachecontrol();
if (cachePeriod != null && cacheControl.getMaxAge() == null) {
cacheControl.setMaxAge(cachePeriod);
}
......@@ -291,8 +301,13 @@ public class WebFluxAutoConfiguration {
static class ResourceChainCustomizerConfiguration {
@Bean
ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {
return new ResourceChainResourceHandlerRegistrationCustomizer();
@SuppressWarnings("deprecation")
ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer(
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
WebProperties webProperties) {
Resources resources = resourceProperties.hasBeenCustomized() ? resourceProperties
: webProperties.getResources();
return new ResourceChainResourceHandlerRegistrationCustomizer(resources);
}
}
......
......@@ -28,7 +28,7 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.error.ErrorAttributeOptions.Include;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
......@@ -82,7 +82,7 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
private final ErrorAttributes errorAttributes;
private final ResourceProperties resourceProperties;
private final Resources resources;
private final TemplateAvailabilityProviders templateAvailabilityProviders;
......@@ -92,13 +92,35 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
private List<ViewResolver> viewResolvers = Collections.emptyList();
public AbstractErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
/**
* Create a new {@code AbstractErrorWebExceptionHandler}.
* @param errorAttributes the error attributes
* @param resourceProperties the resource properties
* @param applicationContext the application context
* @deprecated since 2.4.0 in favor of
* {@link #AbstractErrorWebExceptionHandler(ErrorAttributes, Resources, ApplicationContext)}
*/
@Deprecated
public AbstractErrorWebExceptionHandler(ErrorAttributes errorAttributes,
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
ApplicationContext applicationContext) {
this(errorAttributes, (Resources) resourceProperties, applicationContext);
}
/**
* Create a new {@code AbstractErrorWebExceptionHandler}.
* @param errorAttributes the error attributes
* @param resources the resources configuration properties
* @param applicationContext the application context
* @since 2.4.0
*/
public AbstractErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources,
ApplicationContext applicationContext) {
Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
Assert.notNull(resourceProperties, "ResourceProperties must not be null");
Assert.notNull(resources, "Resources must not be null");
Assert.notNull(applicationContext, "ApplicationContext must not be null");
this.errorAttributes = errorAttributes;
this.resourceProperties = resourceProperties;
this.resources = resources;
this.applicationContext = applicationContext;
this.templateAvailabilityProviders = new TemplateAvailabilityProviders(applicationContext);
}
......@@ -224,7 +246,7 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
}
private Resource resolveResource(String viewName) {
for (String location : this.resourceProperties.getStaticLocations()) {
for (String location : this.resources.getStaticLocations()) {
try {
Resource resource = this.applicationContext.getResource(location);
resource = resource.createRelative(viewName + ".html");
......
......@@ -27,7 +27,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.error.ErrorAttributeOptions.Include;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
......@@ -97,10 +97,27 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
* @param resourceProperties the resources configuration properties
* @param errorProperties the error configuration properties
* @param applicationContext the current application context
* @deprecated since 2.4.0 in favor of
* {@link #DefaultErrorWebExceptionHandler(ErrorAttributes, Resources, ErrorProperties, ApplicationContext)}
*/
public DefaultErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
@Deprecated
public DefaultErrorWebExceptionHandler(ErrorAttributes errorAttributes,
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
ErrorProperties errorProperties, ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, applicationContext);
this(errorAttributes, (Resources) resourceProperties, errorProperties, applicationContext);
}
/**
* Create a new {@code DefaultErrorWebExceptionHandler} instance.
* @param errorAttributes the error attributes
* @param resources the resources configuration properties
* @param errorProperties the error configuration properties
* @param applicationContext the current application context
* @since 2.4.0
*/
public DefaultErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources,
ErrorProperties errorProperties, ApplicationContext applicationContext) {
super(errorAttributes, resources, applicationContext);
this.errorProperties = errorProperties;
}
......
......@@ -25,8 +25,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;
......@@ -48,11 +48,13 @@ import org.springframework.web.reactive.result.view.ViewResolver;
* @author Scott Frederick
* @since 2.0.0
*/
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnClass(WebFluxConfigurer.class)
@AutoConfigureBefore(WebFluxAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class })
@EnableConfigurationProperties({ ServerProperties.class,
org.springframework.boot.autoconfigure.web.ResourceProperties.class, WebProperties.class })
public class ErrorWebFluxAutoConfiguration {
private final ServerProperties serverProperties;
......@@ -65,10 +67,12 @@ public class ErrorWebFluxAutoConfiguration {
@ConditionalOnMissingBean(value = ErrorWebExceptionHandler.class, search = SearchStrategy.CURRENT)
@Order(-1)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes,
ResourceProperties resourceProperties, ObjectProvider<ViewResolver> viewResolvers,
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
WebProperties webProperties, ObjectProvider<ViewResolver> viewResolvers,
ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) {
DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,
resourceProperties, this.serverProperties.getError(), applicationContext);
resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources(),
this.serverProperties.getError(), applicationContext);
exceptionHandler.setViewResolvers(viewResolvers.orderedStream().collect(Collectors.toList()));
exceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());
......
......@@ -33,7 +33,6 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
......@@ -50,9 +49,9 @@ import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvi
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.boot.autoconfigure.validation.ValidatorAdapter;
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties.Strategy;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources.Chain.Strategy;
import org.springframework.boot.autoconfigure.web.format.DateTimeFormatters;
import org.springframework.boot.autoconfigure.web.format.WebConversionService;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.Format;
......@@ -175,15 +174,17 @@ public class WebMvcAutoConfiguration {
// Defined as a nested config to ensure WebMvcConfigurer is not read when not
// on the classpath
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@EnableConfigurationProperties({ WebMvcProperties.class,
org.springframework.boot.autoconfigure.web.ResourceProperties.class, WebProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final ResourceProperties resourceProperties;
private final Resources resourceProperties;
private final WebMvcProperties mvcProperties;
......@@ -197,12 +198,15 @@ public class WebMvcAutoConfiguration {
final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
public WebMvcAutoConfigurationAdapter(
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory,
ObjectProvider<HttpMessageConverters> messageConvertersProvider,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.resourceProperties = resourceProperties.hasBeenCustomized() ? resourceProperties
: webProperties.getResources();
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
......@@ -234,7 +238,6 @@ public class WebMvcAutoConfiguration {
}
@Override
@SuppressWarnings("deprecation")
public void configurePathMatch(PathMatchConfigurer configurer) {
if (this.mvcProperties.getPathmatch()
.getMatchingStrategy() == WebMvcProperties.MatchingStrategy.PATH_PATTERN_PARSER) {
......@@ -259,7 +262,6 @@ public class WebMvcAutoConfiguration {
}
@Override
@SuppressWarnings("deprecation")
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
WebMvcProperties.Contentnegotiation contentnegotiation = this.mvcProperties.getContentnegotiation();
configurer.favorPathExtension(contentnegotiation.isFavorPathExtension());
......@@ -363,7 +365,7 @@ public class WebMvcAutoConfiguration {
@EnableConfigurationProperties(WebProperties.class)
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
private final ResourceProperties resourceProperties;
private final Resources resourceProperties;
private final WebMvcProperties mvcProperties;
......@@ -375,10 +377,13 @@ public class WebMvcAutoConfiguration {
private ResourceLoader resourceLoader;
public EnableWebMvcConfiguration(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
WebProperties webProperties, ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider,
ListableBeanFactory beanFactory) {
this.resourceProperties = resourceProperties;
@SuppressWarnings("deprecation")
public EnableWebMvcConfiguration(
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
WebMvcProperties mvcProperties, WebProperties webProperties,
ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider, ListableBeanFactory beanFactory) {
this.resourceProperties = resourceProperties.hasBeenCustomized() ? resourceProperties
: webProperties.getResources();
this.mvcProperties = mvcProperties;
this.webProperties = webProperties;
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
......@@ -551,8 +556,12 @@ public class WebMvcAutoConfiguration {
static class ResourceChainCustomizerConfiguration {
@Bean
ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer() {
return new ResourceChainResourceHandlerRegistrationCustomizer();
@SuppressWarnings("deprecation")
ResourceChainResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer(
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
WebProperties webProperties) {
return new ResourceChainResourceHandlerRegistrationCustomizer(
resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources());
}
}
......@@ -565,17 +574,20 @@ public class WebMvcAutoConfiguration {
static class ResourceChainResourceHandlerRegistrationCustomizer implements ResourceHandlerRegistrationCustomizer {
@Autowired
private ResourceProperties resourceProperties = new ResourceProperties();
private final Resources resourceProperties;
ResourceChainResourceHandlerRegistrationCustomizer(Resources resourceProperties) {
this.resourceProperties = resourceProperties;
}
@Override
public void customize(ResourceHandlerRegistration registration) {
ResourceProperties.Chain properties = this.resourceProperties.getChain();
Resources.Chain properties = this.resourceProperties.getChain();
configureResourceChain(properties, registration.resourceChain(properties.isCache()));
}
@SuppressWarnings("deprecation")
private void configureResourceChain(ResourceProperties.Chain properties, ResourceChainRegistration chain) {
private void configureResourceChain(Resources.Chain properties, ResourceChainRegistration chain) {
Strategy strategy = properties.getStrategy();
if (properties.isCompressed()) {
chain.addResolver(new EncodedResourceResolver());
......@@ -583,12 +595,14 @@ public class WebMvcAutoConfiguration {
if (strategy.getFixed().isEnabled() || strategy.getContent().isEnabled()) {
chain.addResolver(getVersionResourceResolver(strategy));
}
if (properties.isHtmlApplicationCache()) {
if (properties instanceof org.springframework.boot.autoconfigure.web.ResourceProperties.Chain
&& ((org.springframework.boot.autoconfigure.web.ResourceProperties.Chain) properties)
.isHtmlApplicationCache()) {
chain.addTransformer(new org.springframework.web.servlet.resource.AppCacheManifestTransformer());
}
}
private ResourceResolver getVersionResourceResolver(ResourceProperties.Strategy properties) {
private ResourceResolver getVersionResourceResolver(Strategy properties) {
VersionResourceResolver resolver = new VersionResourceResolver();
if (properties.getFixed().isEnabled()) {
String version = properties.getFixed().getVersion();
......
......@@ -25,7 +25,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.io.Resource;
......@@ -68,7 +68,7 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
private ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final Resources resources;
private final TemplateAvailabilityProviders templateAvailabilityProviders;
......@@ -78,21 +78,35 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
* Create a new {@link DefaultErrorViewResolver} instance.
* @param applicationContext the source application context
* @param resourceProperties resource properties
* @deprecated since 2.4.0 in favour of
* {@link #DefaultErrorViewResolver(ApplicationContext, Resources)}
*/
public DefaultErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties) {
@Deprecated
public DefaultErrorViewResolver(ApplicationContext applicationContext,
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties) {
this(applicationContext, (Resources) resourceProperties);
}
/**
* Create a new {@link DefaultErrorViewResolver} instance.
* @param applicationContext the source application context
* @param resources resource properties
* @since 2.4.0
*/
public DefaultErrorViewResolver(ApplicationContext applicationContext, Resources resources) {
Assert.notNull(applicationContext, "ApplicationContext must not be null");
Assert.notNull(resourceProperties, "ResourceProperties must not be null");
Assert.notNull(resources, "Resources must not be null");
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.resources = resources;
this.templateAvailabilityProviders = new TemplateAvailabilityProviders(applicationContext);
}
DefaultErrorViewResolver(ApplicationContext applicationContext, ResourceProperties resourceProperties,
DefaultErrorViewResolver(ApplicationContext applicationContext, Resources resourceProperties,
TemplateAvailabilityProviders templateAvailabilityProviders) {
Assert.notNull(applicationContext, "ApplicationContext must not be null");
Assert.notNull(resourceProperties, "ResourceProperties must not be null");
Assert.notNull(resourceProperties, "Resources must not be null");
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.resources = resourceProperties;
this.templateAvailabilityProviders = templateAvailabilityProviders;
}
......@@ -116,7 +130,7 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
}
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
for (String location : this.resourceProperties.getStaticLocations()) {
for (String location : this.resources.getStaticLocations()) {
try {
Resource resource = this.applicationContext.getResource(location);
resource = resource.createRelative(viewName + ".html");
......
......@@ -46,8 +46,9 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletPath;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
......@@ -88,7 +89,7 @@ import org.springframework.web.util.HtmlUtils;
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class })
// Load before the main WebMvcAutoConfiguration so that the error View is available
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
@EnableConfigurationProperties({ ServerProperties.class, ResourceProperties.class, WebMvcProperties.class })
@EnableConfigurationProperties({ ServerProperties.class, WebMvcProperties.class })
public class ErrorMvcAutoConfiguration {
private final ServerProperties serverProperties;
......@@ -121,24 +122,29 @@ public class ErrorMvcAutoConfiguration {
return new PreserveErrorControllerTargetClassPostProcessor();
}
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ org.springframework.boot.autoconfigure.web.ResourceProperties.class,
WebProperties.class, WebMvcProperties.class })
static class DefaultErrorViewResolverConfiguration {
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final Resources resources;
DefaultErrorViewResolverConfiguration(ApplicationContext applicationContext,
ResourceProperties resourceProperties) {
org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
WebProperties webProperties) {
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.resources = webProperties.getResources().hasBeenCustomized() ? webProperties.getResources()
: resourceProperties;
}
@Bean
@ConditionalOnBean(DispatcherServlet.class)
@ConditionalOnMissingBean(ErrorViewResolver.class)
DefaultErrorViewResolver conventionErrorViewResolver() {
return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
return new DefaultErrorViewResolver(this.applicationContext, this.resources);
}
}
......
......@@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.web;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
......@@ -46,27 +48,31 @@ class ConditionalOnEnabledResourceChainTests {
assertThat(this.context.containsBean("foo")).isFalse();
}
@Test
void disabledExplicitly() {
load("spring.resources.chain.enabled:false");
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void disabledExplicitly(String prefix) {
load(prefix + "chain.enabled:false");
assertThat(this.context.containsBean("foo")).isFalse();
}
@Test
void enabledViaMainEnabledFlag() {
load("spring.resources.chain.enabled:true");
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void enabledViaMainEnabledFlag(String prefix) {
load(prefix + "chain.enabled:true");
assertThat(this.context.containsBean("foo")).isTrue();
}
@Test
void enabledViaFixedStrategyFlag() {
load("spring.resources.chain.strategy.fixed.enabled:true");
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void enabledViaFixedStrategyFlag(String prefix) {
load(prefix + "chain.strategy.fixed.enabled:true");
assertThat(this.context.containsBean("foo")).isTrue();
}
@Test
void enabledViaContentStrategyFlag() {
load("spring.resources.chain.strategy.content.enabled:true");
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void enabledViaContentStrategyFlag(String prefix) {
load(prefix + "chain.strategy.content.enabled:true");
assertThat(this.context.containsBean("foo")).isTrue();
}
......
......@@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Stephane Nicoll
*/
@Deprecated
class ResourcePropertiesBindingTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
......@@ -60,6 +61,7 @@ class ResourcePropertiesBindingTests {
};
}
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ResourceProperties.class)
static class TestConfiguration {
......
......@@ -20,7 +20,6 @@ import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.ResourceProperties.Cache;
import org.springframework.http.CacheControl;
import static org.assertj.core.api.Assertions.assertThat;
......@@ -31,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Stephane Nicoll
* @author Kristine Jetzke
*/
@Deprecated
class ResourcePropertiesTests {
private final ResourceProperties properties = new ResourceProperties();
......@@ -78,7 +78,7 @@ class ResourcePropertiesTests {
@Test
void cacheControlAllPropertiesSet() {
Cache.Cachecontrol properties = this.properties.getCache().getCachecontrol();
ResourceProperties.Cache.Cachecontrol properties = this.properties.getCache().getCachecontrol();
properties.setMaxAge(Duration.ofSeconds(4));
properties.setCachePrivate(true);
properties.setCachePublic(true);
......@@ -96,7 +96,7 @@ class ResourcePropertiesTests {
@Test
void invalidCacheControlCombination() {
Cache.Cachecontrol properties = this.properties.getCache().getCachecontrol();
ResourceProperties.Cache.Cachecontrol properties = this.properties.getCache().getCachecontrol();
properties.setMaxAge(Duration.ofSeconds(4));
properties.setNoStore(true);
CacheControl cacheControl = properties.toHttpCacheControl();
......
/*
* Copyright 2012-2020 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
*
* https://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;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Binding tests for {@link WebProperties.Resources}.
*
* @author Stephane Nicoll
*/
class WebPropertiesResourcesBindingTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(TestConfiguration.class);
@Test
void staticLocationsExpandArray() {
this.contextRunner
.withPropertyValues("spring.web.resources.static-locations[0]=classpath:/one/",
"spring.web.resources.static-locations[1]=classpath:/two",
"spring.web.resources.static-locations[2]=classpath:/three/",
"spring.web.resources.static-locations[3]=classpath:/four",
"spring.web.resources.static-locations[4]=classpath:/five/",
"spring.web.resources.static-locations[5]=classpath:/six")
.run(assertResourceProperties((properties) -> assertThat(properties.getStaticLocations()).contains(
"classpath:/one/", "classpath:/two/", "classpath:/three/", "classpath:/four/",
"classpath:/five/", "classpath:/six/")));
}
private ContextConsumer<AssertableApplicationContext> assertResourceProperties(Consumer<Resources> consumer) {
return (context) -> {
assertThat(context).hasSingleBean(WebProperties.class);
consumer.accept(context.getBean(WebProperties.class).getResources());
};
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebProperties.class)
static class TestConfiguration {
}
}
/*
* Copyright 2012-2020 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
*
* https://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;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources.Cache;
import org.springframework.http.CacheControl;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WebProperties.Resources}.
*
* @author Stephane Nicoll
* @author Kristine Jetzke
*/
@Deprecated
class WebPropertiesResourcesTests {
private final Resources properties = new WebProperties().getResources();
@Test
void resourceChainNoCustomization() {
assertThat(this.properties.getChain().getEnabled()).isNull();
}
@Test
void resourceChainStrategyEnabled() {
this.properties.getChain().getStrategy().getFixed().setEnabled(true);
assertThat(this.properties.getChain().getEnabled()).isTrue();
}
@Test
void resourceChainEnabled() {
this.properties.getChain().setEnabled(true);
assertThat(this.properties.getChain().getEnabled()).isTrue();
}
@Test
void resourceChainDisabled() {
this.properties.getChain().setEnabled(false);
assertThat(this.properties.getChain().getEnabled()).isFalse();
}
@Test
void defaultStaticLocationsAllEndWithTrailingSlash() {
assertThat(this.properties.getStaticLocations()).allMatch((location) -> location.endsWith("/"));
}
@Test
void customStaticLocationsAreNormalizedToEndWithTrailingSlash() {
this.properties.setStaticLocations(new String[] { "/foo", "/bar", "/baz/" });
String[] actual = this.properties.getStaticLocations();
assertThat(actual).containsExactly("/foo/", "/bar/", "/baz/");
}
@Test
void emptyCacheControl() {
CacheControl cacheControl = this.properties.getCache().getCachecontrol().toHttpCacheControl();
assertThat(cacheControl).isNull();
}
@Test
void cacheControlAllPropertiesSet() {
Cache.Cachecontrol properties = this.properties.getCache().getCachecontrol();
properties.setMaxAge(Duration.ofSeconds(4));
properties.setCachePrivate(true);
properties.setCachePublic(true);
properties.setMustRevalidate(true);
properties.setNoTransform(true);
properties.setProxyRevalidate(true);
properties.setSMaxAge(Duration.ofSeconds(5));
properties.setStaleIfError(Duration.ofSeconds(6));
properties.setStaleWhileRevalidate(Duration.ofSeconds(7));
CacheControl cacheControl = properties.toHttpCacheControl();
assertThat(cacheControl.getHeaderValue())
.isEqualTo("max-age=4, must-revalidate, no-transform, public, private, proxy-revalidate,"
+ " s-maxage=5, stale-if-error=6, stale-while-revalidate=7");
}
@Test
void invalidCacheControlCombination() {
Cache.Cachecontrol properties = this.properties.getCache().getCachecontrol();
properties.setMaxAge(Duration.ofSeconds(4));
properties.setNoStore(true);
CacheControl cacheControl = properties.toHttpCacheControl();
assertThat(cacheControl.getHeaderValue()).isEqualTo("no-store");
}
}
......@@ -33,6 +33,8 @@ import javax.validation.ValidatorFactory;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
......@@ -167,16 +169,18 @@ class WebFluxAutoConfigurationTests {
});
}
@Test
void shouldNotMapResourcesWhenDisabled() {
this.contextRunner.withPropertyValues("spring.resources.add-mappings:false")
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void shouldNotMapResourcesWhenDisabled(String prefix) {
this.contextRunner.withPropertyValues(prefix + ".add-mappings:false")
.run((context) -> assertThat(context.getBean("resourceHandlerMapping"))
.isNotInstanceOf(SimpleUrlHandlerMapping.class));
}
@Test
void resourceHandlerChainEnabled() {
this.contextRunner.withPropertyValues("spring.resources.chain.enabled:true").run((context) -> {
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void resourceHandlerChainEnabled(String prefix) {
this.contextRunner.withPropertyValues(prefix + "chain.enabled:true").run((context) -> {
SimpleUrlHandlerMapping hm = context.getBean("resourceHandlerMapping", SimpleUrlHandlerMapping.class);
assertThat(hm.getUrlMap().get("/**")).isInstanceOf(ResourceWebHandler.class);
ResourceWebHandler staticHandler = (ResourceWebHandler) hm.getUrlMap().get("/**");
......@@ -406,10 +410,11 @@ class WebFluxAutoConfigurationTests {
});
}
@Test
void cachePeriod() {
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void cachePeriod(String prefix) {
Assertions.setExtractBareNamePropertyMethods(false);
this.contextRunner.withPropertyValues("spring.resources.cache.period:5").run((context) -> {
this.contextRunner.withPropertyValues(prefix + "cache.period:5").run((context) -> {
Map<PathPattern, Object> handlerMap = getHandlerMap(context);
assertThat(handlerMap).hasSize(2);
for (Object handler : handlerMap.values()) {
......@@ -422,11 +427,12 @@ class WebFluxAutoConfigurationTests {
Assertions.setExtractBareNamePropertyMethods(true);
}
@Test
void cacheControl() {
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void cacheControl(String prefix) {
Assertions.setExtractBareNamePropertyMethods(false);
this.contextRunner.withPropertyValues("spring.resources.cache.cachecontrol.max-age:5",
"spring.resources.cache.cachecontrol.proxy-revalidate:true").run((context) -> {
this.contextRunner.withPropertyValues(prefix + "cache.cachecontrol.max-age:5",
prefix + "cache.cachecontrol.proxy-revalidate:true").run((context) -> {
Map<PathPattern, Object> handlerMap = getHandlerMap(context);
assertThat(handlerMap).hasSize(2);
for (Object handler : handlerMap.values()) {
......@@ -449,10 +455,10 @@ class WebFluxAutoConfigurationTests {
});
}
@Test
void welcomePageHandlerMapping() {
this.contextRunner.withPropertyValues("spring.resources.static-locations=classpath:/welcome-page/")
.run((context) -> {
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void welcomePageHandlerMapping(String prefix) {
this.contextRunner.withPropertyValues(prefix + "static-locations=classpath:/welcome-page/").run((context) -> {
assertThat(context).getBeans(RouterFunctionMapping.class).hasSize(2);
assertThat(context.getBean("welcomePageRouterFunctionMapping", HandlerMapping.class)).isNotNull()
.extracting("order").isEqualTo(1);
......
......@@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
......@@ -62,7 +62,7 @@ class DefaultErrorWebExceptionHandlerTests {
@Test
void nonStandardErrorStatusCodeShouldNotFail() {
ErrorAttributes errorAttributes = mock(ErrorAttributes.class);
ResourceProperties resourceProperties = new ResourceProperties();
Resources resourceProperties = new Resources();
ErrorProperties errorProperties = new ErrorProperties();
ApplicationContext context = new AnnotationConfigReactiveWebApplicationContext();
given(errorAttributes.getErrorAttributes(any(), any())).willReturn(getErrorAttributes());
......
......@@ -204,15 +204,17 @@ class WebMvcAutoConfigurationTests {
});
}
@Test
void resourceHandlerMappingDisabled() {
this.contextRunner.withPropertyValues("spring.resources.add-mappings:false")
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void resourceHandlerMappingDisabled(String prefix) {
this.contextRunner.withPropertyValues(prefix + "add-mappings:false")
.run((context) -> assertThat(getResourceMappingLocations(context)).hasSize(0));
}
@Test
void resourceHandlerChainEnabled() {
this.contextRunner.withPropertyValues("spring.resources.chain.enabled:true").run((context) -> {
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void resourceHandlerChainEnabled(String prefix) {
this.contextRunner.withPropertyValues(prefix + "chain.enabled:true").run((context) -> {
assertThat(getResourceResolvers(context, "/webjars/**")).hasSize(2);
assertThat(getResourceTransformers(context, "/webjars/**")).hasSize(1);
assertThat(getResourceResolvers(context, "/**")).extractingResultOf("getClass")
......@@ -222,11 +224,13 @@ class WebMvcAutoConfigurationTests {
});
}
@Test
void resourceHandlerFixedStrategyEnabled() {
this.contextRunner.withPropertyValues("spring.resources.chain.strategy.fixed.enabled:true",
"spring.resources.chain.strategy.fixed.version:test",
"spring.resources.chain.strategy.fixed.paths:/**/*.js").run((context) -> {
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void resourceHandlerFixedStrategyEnabled(String prefix) {
this.contextRunner
.withPropertyValues(prefix + "chain.strategy.fixed.enabled:true",
prefix + "chain.strategy.fixed.version:test", prefix + "chain.strategy.fixed.paths:/**/*.js")
.run((context) -> {
assertThat(getResourceResolvers(context, "/webjars/**")).hasSize(3);
assertThat(getResourceTransformers(context, "/webjars/**")).hasSize(2);
assertThat(getResourceResolvers(context, "/**")).extractingResultOf("getClass").containsOnly(
......@@ -239,10 +243,11 @@ class WebMvcAutoConfigurationTests {
});
}
@Test
void resourceHandlerContentStrategyEnabled() {
this.contextRunner.withPropertyValues("spring.resources.chain.strategy.content.enabled:true",
"spring.resources.chain.strategy.content.paths:/**,/*.png").run((context) -> {
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void resourceHandlerContentStrategyEnabled(String prefix) {
this.contextRunner.withPropertyValues(prefix + "chain.strategy.content.enabled:true",
prefix + "chain.strategy.content.paths:/**,/*.png").run((context) -> {
assertThat(getResourceResolvers(context, "/webjars/**")).hasSize(3);
assertThat(getResourceTransformers(context, "/webjars/**")).hasSize(2);
assertThat(getResourceResolvers(context, "/**")).extractingResultOf("getClass").containsOnly(
......@@ -255,25 +260,25 @@ class WebMvcAutoConfigurationTests {
});
}
@Test
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
@SuppressWarnings("deprecation")
void resourceHandlerChainCustomized() {
this.contextRunner
.withPropertyValues("spring.resources.chain.enabled:true", "spring.resources.chain.cache:false",
"spring.resources.chain.strategy.content.enabled:true",
"spring.resources.chain.strategy.content.paths:/**,/*.png",
"spring.resources.chain.strategy.fixed.enabled:true",
"spring.resources.chain.strategy.fixed.version:test",
"spring.resources.chain.strategy.fixed.paths:/**/*.js",
"spring.resources.chain.html-application-cache:true", "spring.resources.chain.compressed:true")
.run((context) -> {
void resourceHandlerChainCustomized(String prefix) {
this.contextRunner.withPropertyValues(prefix + "chain.enabled:true", prefix + "chain.cache:false",
prefix + "chain.strategy.content.enabled:true", prefix + "chain.strategy.content.paths:/**,/*.png",
prefix + "chain.strategy.fixed.enabled:true", prefix + "chain.strategy.fixed.version:test",
prefix + "chain.strategy.fixed.paths:/**/*.js", prefix + "chain.html-application-cache:true",
prefix + "chain.compressed:true").run((context) -> {
assertThat(getResourceResolvers(context, "/webjars/**")).hasSize(3);
assertThat(getResourceTransformers(context, "/webjars/**")).hasSize(2);
assertThat(getResourceTransformers(context, "/webjars/**"))
.hasSize(prefix.equals("spring.resources.") ? 2 : 1);
assertThat(getResourceResolvers(context, "/**")).extractingResultOf("getClass").containsOnly(
EncodedResourceResolver.class, VersionResourceResolver.class, PathResourceResolver.class);
assertThat(getResourceTransformers(context, "/**")).extractingResultOf("getClass").containsOnly(
CssLinkResourceTransformer.class,
org.springframework.web.servlet.resource.AppCacheManifestTransformer.class);
assertThat(getResourceTransformers(context, "/**")).extractingResultOf("getClass")
.containsOnly(prefix.equals("spring.resources.")
? new Class<?>[] { CssLinkResourceTransformer.class,
org.springframework.web.servlet.resource.AppCacheManifestTransformer.class }
: new Class<?>[] { CssLinkResourceTransformer.class });
VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers(context, "/**")
.get(1);
Map<String, VersionStrategy> strategyMap = resolver.getStrategyMap();
......@@ -597,19 +602,20 @@ class WebMvcAutoConfigurationTests {
};
}
@Test
void welcomePageHandlerMappingIsAutoConfigured() {
this.contextRunner.withPropertyValues("spring.resources.static-locations:classpath:/welcome-page/")
.run((context) -> {
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void welcomePageHandlerMappingIsAutoConfigured(String prefix) {
this.contextRunner.withPropertyValues(prefix + "static-locations:classpath:/welcome-page/").run((context) -> {
assertThat(context).hasSingleBean(WelcomePageHandlerMapping.class);
WelcomePageHandlerMapping bean = context.getBean(WelcomePageHandlerMapping.class);
assertThat(bean.getRootHandler()).isNotNull();
});
}
@Test
void welcomePageHandlerIncludesCorsConfiguration() {
this.contextRunner.withPropertyValues("spring.resources.static-locations:classpath:/welcome-page/")
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void welcomePageHandlerIncludesCorsConfiguration(String prefix) {
this.contextRunner.withPropertyValues(prefix + "static-locations:classpath:/welcome-page/")
.withUserConfiguration(CorsConfigurer.class).run((context) -> {
WelcomePageHandlerMapping bean = context.getBean(WelcomePageHandlerMapping.class);
UrlBasedCorsConfigurationSource source = (UrlBasedCorsConfigurationSource) ReflectionTestUtils
......@@ -732,9 +738,10 @@ class WebMvcAutoConfigurationTests {
.run((context) -> assertThat(context).hasNotFailed());
}
@Test
void cachePeriod() {
this.contextRunner.withPropertyValues("spring.resources.cache.period:5").run(this::assertCachePeriod);
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void cachePeriod(String prefix) {
this.contextRunner.withPropertyValues(prefix + "cache.period:5").run(this::assertCachePeriod);
}
private void assertCachePeriod(AssertableWebApplicationContext context) {
......@@ -749,10 +756,11 @@ class WebMvcAutoConfigurationTests {
}
}
@Test
void cacheControl() {
this.contextRunner.withPropertyValues("spring.resources.cache.cachecontrol.max-age:5",
"spring.resources.cache.cachecontrol.proxy-revalidate:true").run(this::assertCacheControl);
@ParameterizedTest
@ValueSource(strings = { "spring.resources.", "spring.web.resources." })
void cacheControl(String prefix) {
this.contextRunner.withPropertyValues(prefix + "cache.cachecontrol.max-age:5",
prefix + "cache.cachecontrol.proxy-revalidate:true").run(this::assertCacheControl);
}
@Test
......
......@@ -30,7 +30,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.Ordered;
......@@ -65,7 +65,7 @@ class DefaultErrorViewResolverTests {
@Mock
private TemplateAvailabilityProvider templateAvailabilityProvider;
private ResourceProperties resourceProperties;
private Resources resourcesProperties;
private Map<String, Object> model = new HashMap<>();
......@@ -75,25 +75,24 @@ class DefaultErrorViewResolverTests {
void setup() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.refresh();
this.resourceProperties = new ResourceProperties();
this.resourcesProperties = new Resources();
TemplateAvailabilityProviders templateAvailabilityProviders = new TestTemplateAvailabilityProviders(
this.templateAvailabilityProvider);
this.resolver = new DefaultErrorViewResolver(applicationContext, this.resourceProperties,
this.resolver = new DefaultErrorViewResolver(applicationContext, this.resourcesProperties,
templateAvailabilityProviders);
}
@Test
void createWhenApplicationContextIsNullShouldThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new DefaultErrorViewResolver(null, new ResourceProperties()))
assertThatIllegalArgumentException().isThrownBy(() -> new DefaultErrorViewResolver(null, new Resources()))
.withMessageContaining("ApplicationContext must not be null");
}
@Test
void createWhenResourcePropertiesIsNullShouldThrowException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new DefaultErrorViewResolver(mock(ApplicationContext.class), null))
.withMessageContaining("ResourceProperties must not be null");
.isThrownBy(() -> new DefaultErrorViewResolver(mock(ApplicationContext.class), (Resources) null))
.withMessageContaining("Resources must not be null");
}
@Test
......@@ -197,7 +196,7 @@ class DefaultErrorViewResolverTests {
private void setResourceLocation(String path) {
String packageName = getClass().getPackage().getName();
this.resourceProperties
this.resourcesProperties
.setStaticLocations(new String[] { "classpath:" + packageName.replace('.', '/') + path + "/" });
}
......
......@@ -23,6 +23,8 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.devtools.logger.DevToolsLogFactory;
import org.springframework.boot.devtools.restart.Restarter;
import org.springframework.boot.devtools.system.DevToolsEnablementDeducer;
......@@ -85,7 +87,9 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro
if (canAddProperties(environment)) {
logger.info(LogMessage.format("Devtools property defaults active! Set '%s' to 'false' to disable",
ENABLED));
environment.getPropertySources().addLast(new MapPropertySource("devtools", PROPERTIES));
Map<String, Object> properties = new HashMap<>(PROPERTIES);
properties.putAll(getResourceProperties(environment));
environment.getPropertySources().addLast(new MapPropertySource("devtools", properties));
}
if (isWebApplication(environment) && !environment.containsProperty(WEB_LOGGING)) {
logger.info(LogMessage.format(
......@@ -95,6 +99,28 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro
}
}
private Map<String, String> getResourceProperties(Environment environment) {
Map<String, String> resourceProperties = new HashMap<>();
String prefix = determineResourcePropertiesPrefix(environment);
resourceProperties.put(prefix + "cache.period", "0");
resourceProperties.put(prefix + "chain.cache", "false");
System.out.println(resourceProperties);
return resourceProperties;
}
@SuppressWarnings("deprecation")
private String determineResourcePropertiesPrefix(Environment environment) {
if (ClassUtils.isPresent("org.springframework.boot.autoconfigure.web.ResourceProperties",
getClass().getClassLoader())) {
BindResult<org.springframework.boot.autoconfigure.web.ResourceProperties> result = Binder.get(environment)
.bind("spring.resources", org.springframework.boot.autoconfigure.web.ResourceProperties.class);
if (result.isBound() && result.get().hasBeenCustomized()) {
return "spring.resources.";
}
}
return "spring.web.resources.";
}
private boolean isLocalApplication(ConfigurableEnvironment environment) {
return environment.getPropertySources().get("remoteUrl") == null;
}
......
......@@ -35,7 +35,8 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.devtools.classpath.ClassPathChangedEvent;
import org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher;
......@@ -113,7 +114,17 @@ class LocalDevToolsAutoConfigurationTests {
@Test
void resourceCachePeriodIsZero() throws Exception {
this.context = getContext(() -> initializeAndRun(WebResourcesConfig.class));
ResourceProperties properties = this.context.getBean(ResourceProperties.class);
Resources properties = this.context.getBean(WebProperties.class).getResources();
assertThat(properties.getCache().getPeriod()).isZero();
}
@SuppressWarnings("deprecation")
@Test
void deprecatedResourceCachePeriodIsZeroWhenDeprecatedResourcePropertiesAreInUse() throws Exception {
this.context = getContext(() -> initializeAndRun(WebResourcesConfig.class,
Collections.singletonMap("spring.resources.add-mappings", false)));
Resources properties = this.context
.getBean(org.springframework.boot.autoconfigure.web.ResourceProperties.class);
assertThat(properties.getCache().getPeriod()).isZero();
}
......@@ -282,9 +293,10 @@ class LocalDevToolsAutoConfigurationTests {
}
@SuppressWarnings("deprecation")
@Configuration(proxyBeanMethods = false)
@Import({ ServletWebServerFactoryAutoConfiguration.class, LocalDevToolsAutoConfiguration.class,
ResourceProperties.class })
@Import({ ServletWebServerFactoryAutoConfiguration.class, LocalDevToolsAutoConfiguration.class, WebProperties.class,
org.springframework.boot.autoconfigure.web.ResourceProperties.class })
static class WebResourcesConfig {
}
......
......@@ -2608,7 +2608,7 @@ For instance, relocating all resources to `/resources/**` can be achieved as fol
static-path-pattern: "/resources/**"
----
You can also customize the static resource locations by using the configprop:spring.resources.static-locations[] property (replacing the default values with a list of directory locations).
You can also customize the static resource locations by using the configprop:spring.web.resources.static-locations[] property (replacing the default values with a list of directory locations).
The root Servlet context path, `"/"`, is automatically added as a location as well.
In addition to the "`standard`" static resource locations mentioned earlier, a special case is made for https://www.webjars.org/[Webjars content].
......@@ -2631,6 +2631,7 @@ To use cache busting, the following configuration configures a cache busting sol
[source,yaml,indent=0,subs="verbatim,quotes,attributes",configprops,configblocks]
----
spring:
web:
resources:
chain:
strategy:
......@@ -2650,6 +2651,7 @@ A "fixed" strategy adds a static version string in the URL without changing the
[source,yaml,indent=0,subs="verbatim,quotes,attributes",configprops,configblocks]
----
spring:
web:
resources:
chain:
strategy:
......@@ -3134,7 +3136,7 @@ For instance, relocating all resources to `/resources/**` can be achieved as fol
static-path-pattern: "/resources/**"
----
You can also customize the static resource locations by using `spring.resources.static-locations`.
You can also customize the static resource locations by using `spring.web.resources.static-locations`.
Doing so replaces the default values with a list of directory locations.
If you do so, the default welcome page detection switches to your custom locations.
So, if there is an `index.html` in any of your locations on startup, it is the home page of the application.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment