Improve Spring Resource Handling support
This commit improves support of the Resource Handling features introduced in Spring Framework 4.1. Those features add new ways to resolve and transform static resources in applications. See [this blog post](https://spring.io/blog/2014/07/24/spring-framework-4-1-handling-static-web-resources) for more details. The `ResourceUrlEncodinFilter` is added for compatible template engines: Velocity and Thymeleaf. It assists them with rewriting the URLs of static resources when rendering templates. New keys are added in the `ResourceProperties` in order to configure the Resource Handling chain. `ResourceResolvers` and `ResourceTransformers` are registered accordingly in `WebMvcAutoConfiguration`. Here is an example of enabling a `ContentVersionStrategy` on all static resources, meaning their names will be changed for cache busting purposes by adding a content hash at the end of the file name. Like "/js/jquery.js -> /js/jquery-872ca6a9fdda9e2c1516a84cff5c3bc6.js". ``` spring.resources.chain.enabled:true spring.resources.chain.strategy.content.enabled:true spring.resources.chain.strategy.content.paths:/** ``` Closes gh-1604 Closes gh-3123
This commit is contained in:
committed by
Stephane Nicoll
parent
e34bdcdd9a
commit
dd561d15cf
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* Copyright 2012-2015 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.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
|
||||
import org.springframework.web.servlet.support.RequestContext;
|
||||
import org.thymeleaf.TemplateEngine;
|
||||
import org.thymeleaf.context.Context;
|
||||
@@ -42,6 +43,7 @@ import org.thymeleaf.templateresolver.TemplateResolver;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -180,4 +182,12 @@ public class ThymeleafAutoConfigurationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerResourceHandlingFilter() throws Exception {
|
||||
this.context.register(ThymeleafAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertNotNull(this.context.getBean(ResourceUrlEncodingFilter.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.View;
|
||||
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
|
||||
import org.springframework.web.servlet.support.RequestContext;
|
||||
import org.springframework.web.servlet.view.velocity.VelocityConfigurer;
|
||||
import org.springframework.web.servlet.view.velocity.VelocityViewResolver;
|
||||
@@ -45,6 +46,7 @@ import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
@@ -183,6 +185,12 @@ public class VelocityAutoConfigurationTests {
|
||||
assertThat(resolver, instanceOf(EmbeddedVelocityViewResolver.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerResourceHandlingFilter() throws Exception {
|
||||
registerAndRefreshContext();
|
||||
assertNotNull(this.context.getBean(ResourceUrlEncodingFilter.class));
|
||||
}
|
||||
|
||||
private void registerAndRefreshContext(String... env) {
|
||||
EnvironmentTestUtils.addEnvironment(this.context, env);
|
||||
this.context.register(VelocityAutoConfiguration.class);
|
||||
|
||||
@@ -60,10 +60,21 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.i18n.FixedLocaleResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
|
||||
import org.springframework.web.servlet.resource.AppCacheManifestTransformer;
|
||||
import org.springframework.web.servlet.resource.CachingResourceResolver;
|
||||
import org.springframework.web.servlet.resource.CachingResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.ContentVersionStrategy;
|
||||
import org.springframework.web.servlet.resource.CssLinkResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.FixedVersionStrategy;
|
||||
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
||||
import org.springframework.web.servlet.resource.ResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceTransformer;
|
||||
import org.springframework.web.servlet.resource.VersionResourceResolver;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
@@ -82,6 +93,7 @@ import static org.junit.Assert.assertThat;
|
||||
* @author Dave Syer
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
public class WebMvcAutoConfigurationTests {
|
||||
|
||||
@@ -124,6 +136,10 @@ public class WebMvcAutoConfigurationTests {
|
||||
assertThat(mappingLocations.get("/webjars/**").size(), equalTo(1));
|
||||
assertThat(mappingLocations.get("/webjars/**").get(0),
|
||||
equalTo((Resource) new ClassPathResource("/META-INF/resources/webjars/")));
|
||||
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(1));
|
||||
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(0));
|
||||
assertThat(getResourceResolvers("/**").size(), equalTo(1));
|
||||
assertThat(getResourceTransformers("/**").size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -151,6 +167,54 @@ public class WebMvcAutoConfigurationTests {
|
||||
assertThat(mappingLocations.size(), equalTo(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resourceHandlerChainEnabled() throws Exception {
|
||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context, "spring.resources.chain.enabled:true");
|
||||
this.context.register(Config.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(2));
|
||||
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(1));
|
||||
assertThat(getResourceResolvers("/**").size(), equalTo(2));
|
||||
assertThat(getResourceTransformers("/**").size(), equalTo(1));
|
||||
|
||||
assertThat(getResourceResolvers("/**"), contains(instanceOf(CachingResourceResolver.class),
|
||||
instanceOf(PathResourceResolver.class)));
|
||||
assertThat(getResourceTransformers("/**"), contains(instanceOf(CachingResourceTransformer.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resourceHandlerChainCustomized() throws Exception {
|
||||
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"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.html5AppCache:true");
|
||||
this.context.register(Config.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(getResourceResolvers("/webjars/**").size(), equalTo(2));
|
||||
assertThat(getResourceTransformers("/webjars/**").size(), equalTo(2));
|
||||
assertThat(getResourceResolvers("/**").size(), equalTo(2));
|
||||
assertThat(getResourceTransformers("/**").size(), equalTo(2));
|
||||
|
||||
assertThat(getResourceResolvers("/**"), contains(
|
||||
instanceOf(VersionResourceResolver.class), instanceOf(PathResourceResolver.class)));
|
||||
assertThat(getResourceTransformers("/**"), contains(instanceOf(CssLinkResourceTransformer.class),
|
||||
instanceOf(AppCacheManifestTransformer.class)));
|
||||
|
||||
VersionResourceResolver resolver = (VersionResourceResolver) getResourceResolvers("/**").get(0);
|
||||
assertThat(resolver.getStrategyMap().get("/*.png"), instanceOf(ContentVersionStrategy.class));
|
||||
assertThat(resolver.getStrategyMap().get("/**/*.js"), instanceOf(FixedVersionStrategy.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noLocaleResolver() throws Exception {
|
||||
load(AllResources.class);
|
||||
@@ -220,6 +284,18 @@ public class WebMvcAutoConfigurationTests {
|
||||
return getMappingLocations(mapping);
|
||||
}
|
||||
|
||||
protected List<ResourceResolver> getResourceResolvers(String mapping) {
|
||||
SimpleUrlHandlerMapping handler = (SimpleUrlHandlerMapping) this.context.getBean("resourceHandlerMapping");
|
||||
ResourceHttpRequestHandler resourceHandler = (ResourceHttpRequestHandler) handler.getHandlerMap().get(mapping);
|
||||
return resourceHandler.getResourceResolvers();
|
||||
}
|
||||
|
||||
protected List<ResourceTransformer> getResourceTransformers(String mapping) {
|
||||
SimpleUrlHandlerMapping handler = (SimpleUrlHandlerMapping) this.context.getBean("resourceHandlerMapping");
|
||||
ResourceHttpRequestHandler resourceHandler = (ResourceHttpRequestHandler) handler.getHandlerMap().get(mapping);
|
||||
return resourceHandler.getResourceTransformers();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<String, List<Resource>> getMappingLocations(HandlerMapping mapping)
|
||||
throws IllegalAccessException {
|
||||
|
||||
Reference in New Issue
Block a user