From f8e1f06d08d0401eb44ef832122235300b1b8fac Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 1 Oct 2013 14:43:38 -0400 Subject: [PATCH] Update Spring MVC Java config for ResourceResolvers --- .../ResourceHandlerRegistration.java | 12 ++++- .../annotation/ResourceHandlerRegistry.java | 54 ++++++++++++++++--- .../WebMvcConfigurationSupport.java | 16 +++++- .../resource/ResourceHttpRequestHandler.java | 17 ++++-- .../resource/ResourceUrlGenerator.java | 45 ++++++++-------- .../ResourceHandlerRegistryTests.java | 32 ++++++++++- .../resource/ResourceUrlGeneratorTests.java | 19 +++---- 7 files changed, 145 insertions(+), 50 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java index 0a876df93f..f34b3b84f2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -111,7 +111,15 @@ public class ResourceHandlerRegistration { * Returns the URL path patterns for the resource handler. */ protected String[] getPathPatterns() { - return pathPatterns; + return this.pathPatterns; + } + + protected List getResourceResolvers() { + return this.resourceResolvers; + } + + protected List getResourceTransformers() { + return this.resourceTransformers; } /** diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java index ce383b5ff0..635710645d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -17,6 +17,7 @@ package org.springframework.web.servlet.config.annotation; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -31,6 +32,8 @@ import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.handler.AbstractHandlerMapping; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; +import org.springframework.web.servlet.resource.ResourceResolver; +import org.springframework.web.servlet.resource.ResourceTransformer; /** * Stores registrations of resource handlers for serving static resources such as images, css files and others @@ -57,8 +60,13 @@ public class ResourceHandlerRegistry { private final List registrations = new ArrayList(); + private List resourceResolvers; + + private List resourceTransformers; + private int order = Integer.MAX_VALUE -1; + public ResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext) { Assert.notNull(applicationContext, "ApplicationContext is required"); this.applicationContext = applicationContext; @@ -76,6 +84,18 @@ public class ResourceHandlerRegistry { return registration; } + /** + * Whether a resource handler has already been registered for the given pathPattern. + */ + public boolean hasMappingForPattern(String pathPattern) { + for (ResourceHandlerRegistration registration : registrations) { + if (Arrays.asList(registration.getPathPatterns()).contains(pathPattern)) { + return true; + } + } + return false; + } + /** * Specify the order to use for resource handling relative to other {@link HandlerMapping}s configured in * the Spring MVC application context. The default value used is {@code Integer.MAX_VALUE-1}. @@ -85,6 +105,22 @@ public class ResourceHandlerRegistry { return this; } + /** + * Configure the {@link ResourceResolver}s to use by default in resource handlers that + * don't have them set. + */ + public void setResourceResolvers(List resourceResolvers) { + this.resourceResolvers = resourceResolvers; + } + + /** + * Configure the {@link ResourceTransformer}s to use by default in resource handlers + * that don't have them set. + */ + public void setResourceTransformers(List transformers) { + this.resourceTransformers = transformers; + } + /** * Return a handler mapping with the mapped resource handlers; or {@code null} in case of no registrations. */ @@ -96,16 +132,22 @@ public class ResourceHandlerRegistry { Map urlMap = new LinkedHashMap(); for (ResourceHandlerRegistration registration : registrations) { for (String pathPattern : registration.getPathPatterns()) { - ResourceHttpRequestHandler requestHandler = registration.getRequestHandler(); - requestHandler.setServletContext(servletContext); - requestHandler.setApplicationContext(applicationContext); + ResourceHttpRequestHandler handler = registration.getRequestHandler(); + handler.setServletContext(servletContext); + handler.setApplicationContext(applicationContext); + if ((this.resourceResolvers != null) && (registration.getResourceResolvers() == null)) { + handler.setResourceResolvers(this.resourceResolvers); + } + if ((this.resourceTransformers != null) && (registration.getResourceTransformers() == null)) { + handler.setResourceTransformers(this.resourceTransformers); + } try { - requestHandler.afterPropertiesSet(); + handler.afterPropertiesSet(); } catch (Exception e) { throw new BeanInitializationException("Failed to init ResourceHttpRequestHandler", e); } - urlMap.put(pathPattern, requestHandler); + urlMap.put(pathPattern, handler); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java index 5ac4c22ff7..915e0eacf8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -70,6 +70,7 @@ import org.springframework.web.servlet.handler.AbstractHandlerMapping; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor; import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; @@ -78,6 +79,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExc import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; +import org.springframework.web.servlet.resource.ResourceUrlGenerator; /** * This is the main class providing the configuration behind the MVC Java config. @@ -306,13 +308,23 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv */ @Bean public HandlerMapping resourceHandlerMapping() { - ResourceHandlerRegistry registry = new ResourceHandlerRegistry(applicationContext, servletContext); + ResourceHandlerRegistry registry = new ResourceHandlerRegistry( + this.applicationContext, this.servletContext); addResourceHandlers(registry); AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping(); return handlerMapping; } + /** + * Return a {@link ResourceUrlGenerator} to use to generate URLs for resources. + */ + @Bean + public ResourceUrlGenerator resourceUrlGenerator() { + SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) resourceHandlerMapping(); + return new ResourceUrlGenerator(hm.getUrlMap()); + } + /** * Override this method to add resource handlers for serving static resources. * @see ResourceHandlerRegistry diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java index 48f48e80a4..0307830438 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java @@ -83,9 +83,9 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H private List locations; - private List resourceResolvers = new ArrayList(); + private final List resourceResolvers = new ArrayList(); - private List resourceTransformers = new ArrayList(); + private final List resourceTransformers = new ArrayList(); public ResourceHttpRequestHandler() { @@ -114,15 +114,24 @@ public class ResourceHttpRequestHandler extends WebContentGenerator implements H * is recommended to add {@link PathResourceResolver} as the last resolver. */ public void setResourceResolvers(List resourceResolvers) { - this.resourceResolvers = resourceResolvers; + this.resourceResolvers.clear(); + if (resourceResolvers != null) { + this.resourceResolvers.addAll(resourceResolvers); + } } public List getResourceResolvers() { return this.resourceResolvers; } + /** + * Configure the list of {@link ResourceTransformer}s to use. + */ public void setResourceTransformers(List transformers) { - this.resourceTransformers = (transformers != null) ? transformers : new ArrayList(); + this.resourceTransformers.clear(); + if (transformers != null) { + this.resourceTransformers.addAll(transformers); + } } public List getResourceTransformers() { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlGenerator.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlGenerator.java index f4086b875a..a2c933ad34 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlGenerator.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceUrlGenerator.java @@ -18,11 +18,13 @@ package org.springframework.web.servlet.resource; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import org.springframework.core.io.Resource; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.Assert; import org.springframework.util.PathMatcher; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; /** @@ -34,39 +36,38 @@ import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; * * @author Rossen Stoyanchev * @since 4.0 + * @see ResourceUrlFilter */ public class ResourceUrlGenerator { - private final List resourceMappings = new ArrayList(); + private final List resourceMappings; /** - * Configure this instance with the handler mappings used to serve resources. It is - * expected that the handler mapping URL map contains handlers of type - * {@link ResourceHttpRequestHandler}. + * Create an instance with a Map of resource handlers. * - * @param handlerMappings resource handler mappings + * @param handlerMap */ - public void setResourceHandlerMappings(List handlerMappings) { - this.resourceMappings.clear(); - if (handlerMappings == null) { - return; - } - for (SimpleUrlHandlerMapping handlerMapping : handlerMappings) { - PathMatcher pathMatcher = handlerMapping.getPathMatcher(); + public ResourceUrlGenerator(Map handlerMap) { + Assert.notNull(handlerMap, "handlerMap is required"); + this.resourceMappings = initResourceMappings(handlerMap); + } - for(Entry entry : handlerMapping.getUrlMap().entrySet()) { - Object value = entry.getValue(); - if (value instanceof ResourceHttpRequestHandler) { - ResourceHttpRequestHandler handler = (ResourceHttpRequestHandler) value; + private static List initResourceMappings(Map handlerMap) { + PathMatcher pathMatcher = new AntPathMatcher(); + List result = new ArrayList(); + for(Entry entry : handlerMap.entrySet()) { + Object value = entry.getValue(); + if (value instanceof ResourceHttpRequestHandler) { + ResourceHttpRequestHandler handler = (ResourceHttpRequestHandler) value; - String pattern = entry.getKey(); - List resolvers = handler.getResourceResolvers(); - List locations = handler.getLocations(); - this.resourceMappings.add(new ResourceMapping(pattern, pathMatcher, resolvers, locations)); - } + String pattern = entry.getKey(); + List resolvers = handler.getResourceResolvers(); + List locations = handler.getLocations(); + result.add(new ResourceMapping(pattern, pathMatcher, resolvers, locations)); } } + return result; } /** diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java index 816cdc8222..3c82e9d005 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java @@ -16,11 +16,12 @@ package org.springframework.web.servlet.config.annotation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import java.util.Arrays; +import java.util.List; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.mock.web.test.MockServletContext; @@ -28,6 +29,10 @@ import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; +import org.springframework.web.servlet.resource.ResourceResolver; +import org.springframework.web.servlet.resource.ResourceTransformer; + +import static org.junit.Assert.*; /** * Test fixture with a {@link ResourceHandlerRegistry}. @@ -84,6 +89,29 @@ public class ResourceHandlerRegistryTests { assertEquals(0, registry.getHandlerMapping().getOrder()); } + @Test + public void hasMappingForPattern() { + assertTrue(registry.hasMappingForPattern("/resources/**")); + assertFalse(registry.hasMappingForPattern("/whatever")); + } + + @Test + public void resourceResolversAndTransformers() { + ResourceResolver resolver = Mockito.mock(ResourceResolver.class); + List resolvers = Arrays.asList(resolver); + registry.setResourceResolvers(resolvers); + + ResourceTransformer transformer = Mockito.mock(ResourceTransformer.class); + List transformers = Arrays.asList(transformer); + registry.setResourceTransformers(transformers); + + SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) registry.getHandlerMapping(); + ResourceHttpRequestHandler handler = (ResourceHttpRequestHandler) hm.getUrlMap().values().iterator().next(); + + assertEquals(resolvers, handler.getResourceResolvers()); + assertEquals(transformers, handler.getResourceTransformers()); + } + private ResourceHttpRequestHandler getHandler(String pathPattern) { SimpleUrlHandlerMapping handlerMapping = (SimpleUrlHandlerMapping) registry.getHandlerMapping(); return (ResourceHttpRequestHandler) handlerMapping.getUrlMap().get(pathPattern); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlGeneratorTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlGeneratorTests.java index 2c3a214922..fcc7e4a662 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlGeneratorTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceUrlGeneratorTests.java @@ -17,7 +17,6 @@ package org.springframework.web.servlet.resource; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,7 +25,6 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import static org.junit.Assert.*; @@ -38,9 +36,9 @@ import static org.junit.Assert.*; */ public class ResourceUrlGeneratorTests { - ResourceHttpRequestHandler handler; + private ResourceHttpRequestHandler handler; - SimpleUrlHandlerMapping mapping; + private Map handlerMap; ResourceUrlGenerator generator; @@ -51,18 +49,15 @@ public class ResourceUrlGeneratorTests { locations.add(new ClassPathResource("test/", getClass())); locations.add(new ClassPathResource("testalternatepath/", getClass())); - Map urlMap = new HashMap(); - handler = new ResourceHttpRequestHandler(); - handler.setLocations(locations); - urlMap.put("/resources/**", handler); + this.handler = new ResourceHttpRequestHandler(); + this.handler.setLocations(locations); - mapping = new SimpleUrlHandlerMapping(); - mapping.setUrlMap(urlMap); + this.handlerMap = new HashMap(); + this.handlerMap.put("/resources/**", handler); } private void initGenerator() { - generator = new ResourceUrlGenerator(); - generator.setResourceHandlerMappings(Collections.singletonList(this.mapping)); + this.generator = new ResourceUrlGenerator(handlerMap); } @Test