001/* 002 * Copyright 2002-2016 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.reactive.config; 018 019import java.util.ArrayList; 020import java.util.Arrays; 021import java.util.List; 022 023import org.springframework.cache.Cache; 024import org.springframework.core.io.Resource; 025import org.springframework.core.io.ResourceLoader; 026import org.springframework.http.CacheControl; 027import org.springframework.lang.Nullable; 028import org.springframework.util.Assert; 029import org.springframework.web.reactive.resource.ResourceWebHandler; 030 031/** 032 * Assist with creating and configuring a static resources handler. 033 * 034 * @author Rossen Stoyanchev 035 * @since 5.0 036 */ 037public class ResourceHandlerRegistration { 038 039 private final ResourceLoader resourceLoader; 040 041 private final String[] pathPatterns; 042 043 private final List<String> locationValues = new ArrayList<>(); 044 045 @Nullable 046 private CacheControl cacheControl; 047 048 @Nullable 049 private ResourceChainRegistration resourceChainRegistration; 050 051 052 /** 053 * Create a {@link ResourceHandlerRegistration} instance. 054 * @param resourceLoader a resource loader for turning a String location 055 * into a {@link Resource} 056 * @param pathPatterns one or more resource URL path patterns 057 */ 058 public ResourceHandlerRegistration(ResourceLoader resourceLoader, String... pathPatterns) { 059 Assert.notNull(resourceLoader, "ResourceLoader is required"); 060 Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling"); 061 this.resourceLoader = resourceLoader; 062 this.pathPatterns = pathPatterns; 063 } 064 065 066 /** 067 * Add one or more resource locations from which to serve static content. 068 * Each location must point to a valid directory. Multiple locations may 069 * be specified as a comma-separated list, and the locations will be checked 070 * for a given resource in the order specified. 071 * 072 * <p>For example, {{@code "/"}, 073 * {@code "classpath:/META-INF/public-web-resources/"}} allows resources to 074 * be served both from the web application root and from any JAR on the 075 * classpath that contains a {@code /META-INF/public-web-resources/} directory, 076 * with resources in the web application root taking precedence. 077 * @return the same {@link ResourceHandlerRegistration} instance, for 078 * chained method invocation 079 */ 080 public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) { 081 this.locationValues.addAll(Arrays.asList(resourceLocations)); 082 return this; 083 } 084 085 /** 086 * Specify the {@link CacheControl} which should be used 087 * by the resource handler. 088 * @param cacheControl the CacheControl configuration to use 089 * @return the same {@link ResourceHandlerRegistration} instance, for 090 * chained method invocation 091 */ 092 public ResourceHandlerRegistration setCacheControl(CacheControl cacheControl) { 093 this.cacheControl = cacheControl; 094 return this; 095 } 096 097 /** 098 * Configure a chain of resource resolvers and transformers to use. This 099 * can be useful, for example, to apply a version strategy to resource URLs. 100 * <p>If this method is not invoked, by default only a simple 101 * {@code PathResourceResolver} is used in order to match URL paths to 102 * resources under the configured locations. 103 * @param cacheResources whether to cache the result of resource resolution; 104 * setting this to "true" is recommended for production (and "false" for 105 * development, especially when applying a version strategy) 106 * @return the same {@link ResourceHandlerRegistration} instance, for 107 * chained method invocation 108 */ 109 public ResourceChainRegistration resourceChain(boolean cacheResources) { 110 this.resourceChainRegistration = new ResourceChainRegistration(cacheResources); 111 return this.resourceChainRegistration; 112 } 113 114 /** 115 * Configure a chain of resource resolvers and transformers to use. This 116 * can be useful, for example, to apply a version strategy to resource URLs. 117 * <p>If this method is not invoked, by default only a simple 118 * {@code PathResourceResolver} is used in order to match URL paths to 119 * resources under the configured locations. 120 * @param cacheResources whether to cache the result of resource resolution; 121 * setting this to "true" is recommended for production (and "false" for 122 * development, especially when applying a version strategy 123 * @param cache the cache to use for storing resolved and transformed resources; 124 * by default a {@link org.springframework.cache.concurrent.ConcurrentMapCache} 125 * is used. Since Resources aren't serializable and can be dependent on the 126 * application host, one should not use a distributed cache but rather an 127 * in-memory cache. 128 * @return the same {@link ResourceHandlerRegistration} instance, for chained method invocation 129 */ 130 public ResourceChainRegistration resourceChain(boolean cacheResources, Cache cache) { 131 this.resourceChainRegistration = new ResourceChainRegistration(cacheResources, cache); 132 return this.resourceChainRegistration; 133 } 134 135 /** 136 * Returns the URL path patterns for the resource handler. 137 */ 138 protected String[] getPathPatterns() { 139 return this.pathPatterns; 140 } 141 142 /** 143 * Returns a {@link ResourceWebHandler} instance. 144 */ 145 protected ResourceWebHandler getRequestHandler() { 146 ResourceWebHandler handler = new ResourceWebHandler(); 147 handler.setLocationValues(this.locationValues); 148 handler.setResourceLoader(this.resourceLoader); 149 if (this.resourceChainRegistration != null) { 150 handler.setResourceResolvers(this.resourceChainRegistration.getResourceResolvers()); 151 handler.setResourceTransformers(this.resourceChainRegistration.getResourceTransformers()); 152 } 153 if (this.cacheControl != null) { 154 handler.setCacheControl(this.cacheControl); 155 } 156 return handler; 157 } 158 159}