Created
November 16, 2012 09:15
-
-
Save eungju/4085759 to your computer and use it in GitHub Desktop.
Servlet Assets Helper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <@resources.stylesheet "default.css" /> | |
| <@resources.javascript "jquery.min.js" /> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <#macro stylesheet path> | |
| <link rel="stylesheet" href="${StaticResources.uri("/resources/" + path)}" type="text/css" /> | |
| </#macro> | |
| <#macro javascript path> | |
| <script src="${StaticResources.uri("/resources/" + path)}" type="text/javascript"></script> | |
| </#macro> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.IOException; | |
| import java.util.concurrent.TimeUnit; | |
| import javax.servlet.ServletContext; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.cache.CacheBuilder; | |
| import com.google.common.cache.CacheLoader; | |
| import com.google.common.cache.LoadingCache; | |
| import com.google.common.hash.HashFunction; | |
| import com.google.common.hash.Hashing; | |
| import com.google.common.io.Resources; | |
| public class StaticResources { | |
| private HashFunction signatureFunction = Hashing.md5(); | |
| private ServletContext context; | |
| private LoadingCache<String, String> signatures; | |
| public StaticResources(ServletContext context, boolean alwaysFresh) { | |
| Preconditions.checkNotNull(context, "The servlet context is required"); | |
| this.context = context; | |
| CacheLoader<String, String> signatureCacheLoader = new CacheLoader<String, String>() { | |
| public String load(String key) { | |
| return signature(key); | |
| } | |
| }; | |
| CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder(); | |
| if (alwaysFresh) { | |
| builder.expireAfterWrite(0, TimeUnit.SECONDS); | |
| } | |
| this.signatures = builder.build(signatureCacheLoader); | |
| } | |
| public String signature(String path) { | |
| try { | |
| return signatureFunction.hashBytes(Resources.toByteArray(context.getResource(path))).toString(); | |
| } catch (IOException e) { | |
| throw new RuntimeException("Unable to read the resource", e); | |
| } | |
| } | |
| /** | |
| * The path must begin with a "/" and is interpreted as relative to the current context root. | |
| */ | |
| public String uri(String path) { | |
| Preconditions.checkArgument(path.startsWith("/"), "The path must begin with a \"/\"."); | |
| StringBuilder result = new StringBuilder(context.getContextPath()); | |
| result.append(path).append("?_s=").append(signatures.getUnchecked(path)); | |
| return result.toString(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import javax.servlet.ServletContext; | |
| import org.springframework.beans.factory.InitializingBean; | |
| import org.springframework.web.context.ServletContextAware; | |
| public class StaticResourcesInitializer implements ServletContextAware, InitializingBean { | |
| private ServletContext context; | |
| private boolean alwaysFresh = false; | |
| public void setServletContext(ServletContext context) { | |
| this.context = context; | |
| } | |
| public void setAlwaysFresh(boolean alwaysFresh) { | |
| this.alwaysFresh = alwaysFresh; | |
| } | |
| @Override | |
| public void afterPropertiesSet() throws Exception { | |
| context.setAttribute("StaticResources", new StaticResources(context, alwaysFresh)); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import static org.junit.Assert.*; | |
| import static org.mockito.Mockito.*; | |
| import javax.servlet.ServletContext; | |
| import org.junit.Before; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.mockito.Mock; | |
| import org.mockito.runners.MockitoJUnitRunner; | |
| import com.google.common.io.Resources; | |
| @RunWith(MockitoJUnitRunner.class) | |
| public class StaticResourcesTest { | |
| private StaticResources dut; | |
| private @Mock ServletContext context; | |
| private String path = "/resources/jquery-1.6.1.min.js"; | |
| private String sig = "9573f9134986b52cff0401ac3218d075"; | |
| @Before public void beforeEach() throws Exception { | |
| dut = new StaticResources(context, true); | |
| when(context.getResource(path)).thenReturn(Resources.getResource("webapps" + path)); | |
| } | |
| @Test public void signature() { | |
| assertEquals(sig, dut.signature(path)); | |
| } | |
| @Test public void uri_with_root_context_path() { | |
| when(context.getContextPath()).thenReturn(""); | |
| assertEquals(path + "?_s=" + sig, dut.uri(path)); | |
| } | |
| @Test(expected=IllegalArgumentException.class) public void uri_throws_exception_when_the_path_does_not_start_with_slash() { | |
| when(context.getContextPath()).thenReturn(""); | |
| assertEquals(path + "?_s=" + sig, dut.uri("resources/x.js")); | |
| } | |
| @Test public void uri_with_none_root_context_path() { | |
| when(context.getContextPath()).thenReturn("/login"); | |
| assertEquals("/login" + path + "?_s=" + sig, dut.uri(path)); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment