1 /*
2  * Copyright 2002-2011 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.springframework.web.servlet.config.annotation;
18 
19 import java.util.ArrayList;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23 
24 import javax.servlet.ServletContext;
25 
26 import org.springframework.context.ApplicationContext;
27 import org.springframework.util.Assert;
28 import org.springframework.web.HttpRequestHandler;
29 import org.springframework.web.servlet.HandlerMapping;
30 import org.springframework.web.servlet.handler.AbstractHandlerMapping;
31 import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
32 import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
33 
34 /**
35  * Stores registrations of resource handlers for serving static resources such as images, css files and others
36  * through Spring MVC including setting cache headers optimized for efficient loading in a web browser.
37  * Resources can be served out of locations under web application root, from the classpath, and others.
38  *
39  * <p>To create a resource handler, use {@link #addResourceHandler(String...)} providing the URL path patterns
40  * for which the handler should be invoked to serve static resources (e.g. {@code "/resources/**"}).
41  *
42  * <p>Then use additional methods on the returned {@link ResourceHandlerRegistration} to add one or more
43  * locations from which to serve static content from (e.g. {{@code "/"},
44  * {@code "classpath:/META-INF/public-web-resources/"}}) or to specify a cache period for served resources.
45  *
46  * @author Rossen Stoyanchev
47  * @since 3.1
48  *
49  * @see DefaultServletHandlerConfigurer
50  */
51 public class ResourceHandlerRegistry {
52 
53 	private final ServletContext servletContext;
54 
55 	private final ApplicationContext applicationContext;
56 
57 	private final List<ResourceHandlerRegistration> registrations = new ArrayList<ResourceHandlerRegistration>();
58 
59 	private int order = Integer.MAX_VALUE -1;
60 
ResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext)61 	public ResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext) {
62 		Assert.notNull(applicationContext, "ApplicationContext is required");
63 		this.applicationContext = applicationContext;
64 		this.servletContext = servletContext;
65 	}
66 
67 	/**
68 	 * Add a resource handler for serving static resources based on the specified URL path patterns.
69 	 * The handler will be invoked for every incoming request that matches to one of the specified path patterns.
70 	 * @return A {@link ResourceHandlerRegistration} to use to further configure the registered resource handler.
71 	 */
addResourceHandler(String... pathPatterns)72 	public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {
73 		ResourceHandlerRegistration registration = new ResourceHandlerRegistration(applicationContext, pathPatterns);
74 		registrations.add(registration);
75 		return registration;
76 	}
77 
78 	/**
79 	 * Specify the order to use for resource handling relative to other {@link HandlerMapping}s configured in
80 	 * the Spring MVC application context. The default value used is {@code Integer.MAX_VALUE-1}.
81 	 */
setOrder(int order)82 	public ResourceHandlerRegistry setOrder(int order) {
83 		this.order = order;
84 		return this;
85 	}
86 
87 	/**
88 	 * Return a handler mapping with the mapped resource handlers; or {@code null} in case of no registrations.
89 	 */
getHandlerMapping()90 	protected AbstractHandlerMapping getHandlerMapping() {
91 		if (registrations.isEmpty()) {
92 			return null;
93 		}
94 
95 		Map<String, HttpRequestHandler> urlMap = new LinkedHashMap<String, HttpRequestHandler>();
96 		for (ResourceHandlerRegistration registration : registrations) {
97 			for (String pathPattern : registration.getPathPatterns()) {
98 				ResourceHttpRequestHandler requestHandler = registration.getRequestHandler();
99 				requestHandler.setServletContext(servletContext);
100 				requestHandler.setApplicationContext(applicationContext);
101 				urlMap.put(pathPattern, requestHandler);
102 			}
103 		}
104 
105 		SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
106 		handlerMapping.setOrder(order);
107 		handlerMapping.setUrlMap(urlMap);
108 		return handlerMapping;
109 	}
110 
111 }