Allow custom resource handlers to provide favicon.ico
Closes gh-17381
This commit is contained in:
parent
a3e94f4412
commit
8aed06452d
|
@ -17,9 +17,7 @@
|
|||
package org.springframework.boot.autoconfigure.web.servlet;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
@ -66,7 +64,6 @@ import org.springframework.context.annotation.Import;
|
|||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
|
@ -106,7 +103,6 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
|
|||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.FixedLocaleResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
|
||||
|
@ -114,7 +110,6 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
|||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.springframework.web.servlet.resource.AppCacheManifestTransformer;
|
||||
import org.springframework.web.servlet.resource.EncodedResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
|
||||
import org.springframework.web.servlet.resource.ResourceResolver;
|
||||
import org.springframework.web.servlet.resource.ResourceUrlProvider;
|
||||
import org.springframework.web.servlet.resource.VersionResourceResolver;
|
||||
|
@ -370,48 +365,13 @@ public class WebMvcAutoConfiguration {
|
|||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(value = "spring.mvc.favicon.enabled", matchIfMissing = true)
|
||||
public static class FaviconConfiguration implements ResourceLoaderAware {
|
||||
|
||||
private final ResourceProperties resourceProperties;
|
||||
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
public FaviconConfiguration(ResourceProperties resourceProperties) {
|
||||
this.resourceProperties = resourceProperties;
|
||||
}
|
||||
public static class FaviconConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleUrlHandlerMapping faviconHandlerMapping(FaviconRequestHandler handler) {
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
|
||||
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", handler));
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FaviconRequestHandler faviconRequestHandler() {
|
||||
return new FaviconRequestHandler(resolveFaviconLocations());
|
||||
}
|
||||
|
||||
private List<Resource> resolveFaviconLocations() {
|
||||
String[] staticLocations = getResourceLocations(this.resourceProperties.getStaticLocations());
|
||||
List<Resource> locations = new ArrayList<>(staticLocations.length + 1);
|
||||
Arrays.stream(staticLocations).map(this.resourceLoader::getResource).forEach(locations::add);
|
||||
locations.add(new ClassPathResource("/"));
|
||||
return Collections.unmodifiableList(locations);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class FaviconRequestHandler extends ResourceHttpRequestHandler {
|
||||
|
||||
FaviconRequestHandler(List<Resource> locations) {
|
||||
setLocations(locations);
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
if (!registry.hasMappingForPattern("favicon.ico")) {
|
||||
registry.addResourceHandler("favicon.ico").addResourceLocations("classpath:favicon.ico");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -147,7 +148,7 @@ class WebMvcAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
void handlerMappingsCreated() {
|
||||
this.contextRunner.run((context) -> assertThat(context).getBeans(HandlerMapping.class).hasSize(6));
|
||||
this.contextRunner.run((context) -> assertThat(context).getBeans(HandlerMapping.class).hasSize(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -195,7 +196,7 @@ class WebMvcAutoConfigurationTests {
|
|||
@Test
|
||||
void resourceHandlerMappingDisabled() {
|
||||
this.contextRunner.withPropertyValues("spring.resources.add-mappings:false")
|
||||
.run((context) -> assertThat(context.getBean("resourceHandlerMapping")).isEqualTo(null));
|
||||
.run((context) -> assertThat(getResourceMappingLocations(context)).hasSize(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -379,25 +380,14 @@ class WebMvcAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
void faviconMapping() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).getBeanNames(ResourceHttpRequestHandler.class).contains("faviconRequestHandler");
|
||||
assertThat(context).getBeans(SimpleUrlHandlerMapping.class).containsKey("faviconHandlerMapping");
|
||||
assertThat(getFaviconMappingLocations(context).get("/**/favicon.ico")).hasSize(6);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void faviconMappingUsesStaticLocations() {
|
||||
this.contextRunner.withPropertyValues("spring.resources.static-locations=classpath:/static")
|
||||
.run((context) -> assertThat(getFaviconMappingLocations(context).get("/**/favicon.ico")).hasSize(3));
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(getResourceMappingLocations(context).get("/favicon.ico")).hasSize(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void faviconMappingDisabled() {
|
||||
this.contextRunner.withPropertyValues("spring.mvc.favicon.enabled:false").run((context) -> {
|
||||
assertThat(context).getBeans(ResourceHttpRequestHandler.class).doesNotContainKey("faviconRequestHandler");
|
||||
assertThat(context).getBeans(SimpleUrlHandlerMapping.class).doesNotContainKey("faviconHandlerMapping");
|
||||
});
|
||||
this.contextRunner.withPropertyValues("spring.mvc.favicon.enabled:false")
|
||||
.run((context) -> assertThat(getResourceMappingLocations(context).get("/favicon.ico")).isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -667,11 +657,14 @@ class WebMvcAutoConfigurationTests {
|
|||
|
||||
private void assertCachePeriod(AssertableWebApplicationContext context) {
|
||||
Map<String, Object> handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class));
|
||||
assertThat(handlerMap).hasSize(2);
|
||||
for (Object handler : handlerMap.values()) {
|
||||
if (handler instanceof ResourceHttpRequestHandler) {
|
||||
assertThat(((ResourceHttpRequestHandler) handler).getCacheSeconds()).isEqualTo(5);
|
||||
assertThat(((ResourceHttpRequestHandler) handler).getCacheControl()).isNull();
|
||||
assertThat(handlerMap).hasSize(3);
|
||||
for (Entry<String, Object> entry : handlerMap.entrySet()) {
|
||||
if (!entry.getKey().equals("/favicon.ico")) {
|
||||
Object handler = entry.getValue();
|
||||
if (handler instanceof ResourceHttpRequestHandler) {
|
||||
assertThat(((ResourceHttpRequestHandler) handler).getCacheSeconds()).isEqualTo(5);
|
||||
assertThat(((ResourceHttpRequestHandler) handler).getCacheControl()).isNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -788,7 +781,7 @@ class WebMvcAutoConfigurationTests {
|
|||
|
||||
private void assertCacheControl(AssertableWebApplicationContext context) {
|
||||
Map<String, Object> handlerMap = getHandlerMap(context.getBean("resourceHandlerMapping", HandlerMapping.class));
|
||||
assertThat(handlerMap).hasSize(2);
|
||||
assertThat(handlerMap).hasSize(3);
|
||||
for (Object handler : handlerMap.keySet()) {
|
||||
if (handler instanceof ResourceHttpRequestHandler) {
|
||||
assertThat(((ResourceHttpRequestHandler) handler).getCacheSeconds()).isEqualTo(-1);
|
||||
|
@ -798,10 +791,6 @@ class WebMvcAutoConfigurationTests {
|
|||
}
|
||||
}
|
||||
|
||||
protected Map<String, List<Resource>> getFaviconMappingLocations(ApplicationContext context) {
|
||||
return getMappingLocations(context.getBean("faviconHandlerMapping", HandlerMapping.class));
|
||||
}
|
||||
|
||||
protected Map<String, List<Resource>> getResourceMappingLocations(ApplicationContext context) {
|
||||
return getMappingLocations(context.getBean("resourceHandlerMapping", HandlerMapping.class));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue