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