001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.config.annotation; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.List; 022 023import org.springframework.cache.Cache; 024import org.springframework.http.CacheControl; 025import org.springframework.util.Assert; 026import org.springframework.web.servlet.resource.PathResourceResolver; 027import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; 028 029/** 030 * Encapsulates information required to create a resource handler. 031 * 032 * @author Rossen Stoyanchev 033 * @author Keith Donald 034 * @author Brian Clozel 035 * @since 3.1 036 */ 037public class ResourceHandlerRegistration { 038 039 private final String[] pathPatterns; 040 041 private final List<String> locationValues = new ArrayList<String>(); 042 043 private Integer cachePeriod; 044 045 private CacheControl cacheControl; 046 047 private ResourceChainRegistration resourceChainRegistration; 048 049 050 /** 051 * Create a {@link ResourceHandlerRegistration} instance. 052 * @param pathPatterns one or more resource URL path patterns 053 */ 054 public ResourceHandlerRegistration(String... pathPatterns) { 055 Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling."); 056 this.pathPatterns = pathPatterns; 057 } 058 059 060 /** 061 * Add one or more resource locations from which to serve static content. 062 * Each location must point to a valid directory. Multiple locations may 063 * be specified as a comma-separated list, and the locations will be checked 064 * for a given resource in the order specified. 065 * <p>For example, {{@code "/"}, {@code "classpath:/META-INF/public-web-resources/"}} 066 * allows resources to be served both from the web application root and 067 * from any JAR on the classpath that contains a 068 * {@code /META-INF/public-web-resources/} directory, with resources in the 069 * web application root taking precedence. 070 * <p>For {@link org.springframework.core.io.UrlResource URL-based resources} 071 * (e.g. files, HTTP URLs, etc) this method supports a special prefix to 072 * indicate the charset associated with the URL so that relative paths 073 * appended to it can be encoded correctly, e.g. 074 * {@code [charset=Windows-31J]https://example.org/path}. 075 * @return the same {@link ResourceHandlerRegistration} instance, for 076 * chained method invocation 077 */ 078 public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) { 079 this.locationValues.addAll(Arrays.asList(resourceLocations)); 080 return this; 081 } 082 083 /** 084 * Specify the cache period for the resources served by the resource handler, in seconds. The default is to not 085 * send any cache headers but to rely on last-modified timestamps only. Set to 0 in order to send cache headers 086 * that prevent caching, or to a positive number of seconds to send cache headers with the given max-age value. 087 * @param cachePeriod the time to cache resources in seconds 088 * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation 089 */ 090 public ResourceHandlerRegistration setCachePeriod(Integer cachePeriod) { 091 this.cachePeriod = cachePeriod; 092 return this; 093 } 094 095 /** 096 * Specify the {@link org.springframework.http.CacheControl} which should be used 097 * by the resource handler. 098 * <p>Setting a custom value here will override the configuration set with {@link #setCachePeriod}. 099 * @param cacheControl the CacheControl configuration to use 100 * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation 101 * @since 4.2 102 */ 103 public ResourceHandlerRegistration setCacheControl(CacheControl cacheControl) { 104 this.cacheControl = cacheControl; 105 return this; 106 } 107 108 /** 109 * Configure a chain of resource resolvers and transformers to use. This 110 * can be useful, for example, to apply a version strategy to resource URLs. 111 * <p>If this method is not invoked, by default only a simple 112 * {@link PathResourceResolver} is used in order to match URL paths to 113 * resources under the configured locations. 114 * @param cacheResources whether to cache the result of resource resolution; 115 * setting this to "true" is recommended for production (and "false" for 116 * development, especially when applying a version strategy) 117 * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation 118 * @since 4.1 119 */ 120 public ResourceChainRegistration resourceChain(boolean cacheResources) { 121 this.resourceChainRegistration = new ResourceChainRegistration(cacheResources); 122 return this.resourceChainRegistration; 123 } 124 125 /** 126 * Configure a chain of resource resolvers and transformers to use. This 127 * can be useful, for example, to apply a version strategy to resource URLs. 128 * <p>If this method is not invoked, by default only a simple 129 * {@link PathResourceResolver} is used in order to match URL paths to 130 * resources under the configured locations. 131 * @param cacheResources whether to cache the result of resource resolution; 132 * setting this to "true" is recommended for production (and "false" for 133 * development, especially when applying a version strategy 134 * @param cache the cache to use for storing resolved and transformed resources; 135 * by default a {@link org.springframework.cache.concurrent.ConcurrentMapCache} 136 * is used. Since Resources aren't serializable and can be dependent on the 137 * application host, one should not use a distributed cache but rather an 138 * in-memory cache. 139 * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation 140 * @since 4.1 141 */ 142 public ResourceChainRegistration resourceChain(boolean cacheResources, Cache cache) { 143 this.resourceChainRegistration = new ResourceChainRegistration(cacheResources, cache); 144 return this.resourceChainRegistration; 145 } 146 147 148 /** 149 * Return the URL path patterns for the resource handler. 150 */ 151 protected String[] getPathPatterns() { 152 return this.pathPatterns; 153 } 154 155 /** 156 * Return a {@link ResourceHttpRequestHandler} instance. 157 */ 158 protected ResourceHttpRequestHandler getRequestHandler() { 159 ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler(); 160 if (this.resourceChainRegistration != null) { 161 handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers()); 162 handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers()); 163 } 164 handler.setLocationValues(this.locationValues); 165 if (this.cacheControl != null) { 166 handler.setCacheControl(this.cacheControl); 167 } 168 else if (this.cachePeriod != null) { 169 handler.setCacheSeconds(this.cachePeriod); 170 } 171 return handler; 172 } 173 174}