/* * Copyright 2012-2017 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure.web; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; /** * Properties used to configure resource handling. * * @author Phillip Webb * @author Brian Clozel * @author Dave Syer * @author Venil Noronha * @since 1.1.0 */ @ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false) public class ResourceProperties implements ResourceLoaderAware { private static final String[] SERVLET_RESOURCE_LOCATIONS = { "/" }; private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" }; private static final String[] RESOURCE_LOCATIONS; static { RESOURCE_LOCATIONS = new String[CLASSPATH_RESOURCE_LOCATIONS.length + SERVLET_RESOURCE_LOCATIONS.length]; System.arraycopy(SERVLET_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, 0, SERVLET_RESOURCE_LOCATIONS.length); System.arraycopy(CLASSPATH_RESOURCE_LOCATIONS, 0, RESOURCE_LOCATIONS, SERVLET_RESOURCE_LOCATIONS.length, CLASSPATH_RESOURCE_LOCATIONS.length); } /** * Locations of static resources. Defaults to classpath:[/META-INF/resources/, * /resources/, /static/, /public/] plus context:/ (the root of the servlet context). */ private String[] staticLocations = RESOURCE_LOCATIONS; /** * Cache period for the resources served by the resource handler, in seconds. */ private Integer cachePeriod; /** * Enable default resource handling. */ private boolean addMappings = true; private final Chain chain = new Chain(); private ResourceLoader resourceLoader; @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } public String[] getStaticLocations() { return this.staticLocations; } public void setStaticLocations(String[] staticLocations) { this.staticLocations = staticLocations; } public Resource getWelcomePage() { for (String location : getStaticWelcomePageLocations()) { Resource resource = this.resourceLoader.getResource(location); try { if (resource.exists()) { resource.getURL(); return resource; } } catch (Exception ex) { // Ignore } } return null; } private String[] getStaticWelcomePageLocations() { String[] result = new String[this.staticLocations.length]; for (int i = 0; i < result.length; i++) { String location = this.staticLocations[i]; if (!location.endsWith("/")) { location = location + "/"; } result[i] = location + "index.html"; } return result; } public List<Resource> resolveFaviconLocations() { List<Resource> locations = new ArrayList<>(this.staticLocations.length + 1); if (this.resourceLoader != null) { for (String location : this.staticLocations) { locations.add(this.resourceLoader.getResource(location)); } } locations.add(new ClassPathResource("/")); return Collections.unmodifiableList(locations); } public Integer getCachePeriod() { return this.cachePeriod; } public void setCachePeriod(Integer cachePeriod) { this.cachePeriod = cachePeriod; } public boolean isAddMappings() { return this.addMappings; } public void setAddMappings(boolean addMappings) { this.addMappings = addMappings; } public Chain getChain() { return this.chain; } /** * Configuration for the Spring Resource Handling chain. */ public static class Chain { /** * Enable the Spring Resource Handling chain. Disabled by default unless at least * one strategy has been enabled. */ private Boolean enabled; /** * Enable caching in the Resource chain. */ private boolean cache = true; /** * Enable HTML5 application cache manifest rewriting. */ private boolean htmlApplicationCache = false; /** * Enable resolution of already gzipped resources. Checks for a resource name * variant with the "*.gz" extension. */ private boolean gzipped = false; private final Strategy strategy = new Strategy(); /** * Return whether the resource chain is enabled. Return {@code null} if no * specific settings are present. * @return whether the resource chain is enabled or {@code null} if no specified * settings are present. */ public Boolean getEnabled() { return getEnabled(getStrategy().getFixed().isEnabled(), getStrategy().getContent().isEnabled(), this.enabled); } public void setEnabled(boolean enabled) { this.enabled = enabled; } public boolean isCache() { return this.cache; } public void setCache(boolean cache) { this.cache = cache; } public Strategy getStrategy() { return this.strategy; } public boolean isHtmlApplicationCache() { return this.htmlApplicationCache; } public void setHtmlApplicationCache(boolean htmlApplicationCache) { this.htmlApplicationCache = htmlApplicationCache; } public boolean isGzipped() { return this.gzipped; } public void setGzipped(boolean gzipped) { this.gzipped = gzipped; } static Boolean getEnabled(boolean fixedEnabled, boolean contentEnabled, Boolean chainEnabled) { return (fixedEnabled || contentEnabled ? Boolean.TRUE : chainEnabled); } } /** * Strategies for extracting and embedding a resource version in its URL path. */ public static class Strategy { private final Fixed fixed = new Fixed(); private final Content content = new Content(); public Fixed getFixed() { return this.fixed; } public Content getContent() { return this.content; } } /** * Version Strategy based on content hashing. */ public static class Content { /** * Enable the content Version Strategy. */ private boolean enabled; /** * Comma-separated list of patterns to apply to the Version Strategy. */ private String[] paths = new String[] { "/**" }; public boolean isEnabled() { return this.enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public String[] getPaths() { return this.paths; } public void setPaths(String[] paths) { this.paths = paths; } } /** * Version Strategy based on a fixed version string. */ public static class Fixed { /** * Enable the fixed Version Strategy. */ private boolean enabled; /** * Comma-separated list of patterns to apply to the Version Strategy. */ private String[] paths = new String[] { "/**" }; /** * Version string to use for the Version Strategy. */ private String version; public boolean isEnabled() { return this.enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public String[] getPaths() { return this.paths; } public void setPaths(String[] paths) { this.paths = paths; } public String getVersion() { return this.version; } public void setVersion(String version) { this.version = version; } } }