From 2d14bd706650c94cb212722d566dc3a4244892a5 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 26 Oct 2018 13:48:45 +0200 Subject: [PATCH] Configure ResourceUrlProvider in WebFlux Prior to this commit, no `ResourceUrlProvider` was configured in WebFlux (no bean was contributed by the WebFlux infrastructure). Also, several `ResourceTransformer` instances that extend the `ResourceTransformerSupport` base class need a `ResourceUrlProvider` to resolve absolute URLs when rewriting resource URLs. At this point, no `ResourceUrlProvider` was configured and they could only resolve relative URLs. This commit contributes a new `ResourceUrlProvider` to the WebFlux configuration; this bean can be reused by the WebFlux infrastructure and application code. This also automatically configure this shared `ResourceUrlProvider` instance on the resource chain where needed. Issue: SPR-17433 (Cherry-picked from fc957e95bb) --- .../config/ResourceHandlerRegistry.java | 24 ++++++++++++++++++- .../config/WebFluxConfigurationSupport.java | 8 +++++++ .../config/ResourceHandlerRegistryTests.java | 10 ++++++-- .../WebFluxConfigurationSupportTests.java | 10 ++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistry.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistry.java index 3d9ae6f5957..d891131ea49 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistry.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/ResourceHandlerRegistry.java @@ -28,6 +28,8 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.lang.Nullable; import org.springframework.web.reactive.handler.AbstractUrlHandlerMapping; import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; +import org.springframework.web.reactive.resource.ResourceTransformerSupport; +import org.springframework.web.reactive.resource.ResourceUrlProvider; import org.springframework.web.reactive.resource.ResourceWebHandler; import org.springframework.web.server.WebHandler; @@ -49,6 +51,7 @@ import org.springframework.web.server.WebHandler; * period for served resources. * * @author Rossen Stoyanchev + * @author Brian Clozel * @since 5.0 */ public class ResourceHandlerRegistry { @@ -57,7 +60,10 @@ public class ResourceHandlerRegistry { private final List registrations = new ArrayList<>(); - private int order = Ordered.LOWEST_PRECEDENCE -1; + private int order = Ordered.LOWEST_PRECEDENCE - 1; + + @Nullable + private ResourceUrlProvider resourceUrlProvider; /** @@ -69,6 +75,17 @@ public class ResourceHandlerRegistry { this.resourceLoader = resourceLoader; } + /** + * Configure the {@link ResourceUrlProvider} that can be used by + * {@link org.springframework.web.reactive.resource.ResourceTransformer} instances. + * @param resourceUrlProvider the resource URL provider to use + * @since 5.1.2 + */ + public void setResourceUrlProvider(@Nullable ResourceUrlProvider resourceUrlProvider) { + this.resourceUrlProvider = resourceUrlProvider; + } + + /** * Add a resource handler for serving static resources based on the specified @@ -121,6 +138,11 @@ public class ResourceHandlerRegistry { for (ResourceHandlerRegistration registration : this.registrations) { for (String pathPattern : registration.getPathPatterns()) { ResourceWebHandler handler = registration.getRequestHandler(); + handler.getResourceTransformers().forEach(transformer -> { + if (transformer instanceof ResourceTransformerSupport) { + ((ResourceTransformerSupport) transformer).setResourceUrlProvider(this.resourceUrlProvider); + } + }); try { handler.afterPropertiesSet(); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java index 3b7b8d42ed6..2cdbc779f6f 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java @@ -53,6 +53,7 @@ import org.springframework.web.reactive.function.server.support.RouterFunctionMa import org.springframework.web.reactive.function.server.support.ServerResponseResultHandler; import org.springframework.web.reactive.handler.AbstractHandlerMapping; import org.springframework.web.reactive.handler.WebFluxResponseStatusExceptionHandler; +import org.springframework.web.reactive.resource.ResourceUrlProvider; import org.springframework.web.reactive.result.SimpleHandlerAdapter; import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; @@ -72,6 +73,7 @@ import org.springframework.web.server.i18n.LocaleContextResolver; *

Import directly or extend and override protected methods to customize. * * @author Rossen Stoyanchev + * @author Brian Clozel * @since 5.0 */ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -218,6 +220,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { resourceLoader = new DefaultResourceLoader(); } ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader); + registry.setResourceUrlProvider(resourceUrlProvider()); addResourceHandlers(registry); AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); @@ -238,6 +241,11 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { return handlerMapping; } + @Bean + public ResourceUrlProvider resourceUrlProvider() { + return new ResourceUrlProvider(); + } + /** * Override this method to add resource handlers for serving static resources. * @see ResourceHandlerRegistry diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/ResourceHandlerRegistryTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/ResourceHandlerRegistryTests.java index 0dbc0339197..1b10e8319f1 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/ResourceHandlerRegistryTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/ResourceHandlerRegistryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -43,6 +43,8 @@ import org.springframework.web.reactive.resource.CssLinkResourceTransformer; import org.springframework.web.reactive.resource.PathResourceResolver; import org.springframework.web.reactive.resource.ResourceResolver; import org.springframework.web.reactive.resource.ResourceTransformer; +import org.springframework.web.reactive.resource.ResourceTransformerSupport; +import org.springframework.web.reactive.resource.ResourceUrlProvider; import org.springframework.web.reactive.resource.ResourceWebHandler; import org.springframework.web.reactive.resource.VersionResourceResolver; import org.springframework.web.reactive.resource.WebJarsResourceResolver; @@ -120,8 +122,11 @@ public class ResourceHandlerRegistryTests { @Test public void resourceChain() throws Exception { + ResourceUrlProvider resourceUrlProvider = Mockito.mock(ResourceUrlProvider.class); + this.registry.setResourceUrlProvider(resourceUrlProvider); ResourceResolver mockResolver = Mockito.mock(ResourceResolver.class); - ResourceTransformer mockTransformer = Mockito.mock(ResourceTransformer.class); + ResourceTransformerSupport mockTransformer = Mockito.mock(ResourceTransformerSupport.class); + this.registration.resourceChain(true).addResolver(mockResolver).addTransformer(mockTransformer); ResourceWebHandler handler = getHandler("/resources/**"); @@ -138,6 +143,7 @@ public class ResourceHandlerRegistryTests { assertThat(transformers, Matchers.hasSize(2)); assertThat(transformers.get(0), Matchers.instanceOf(CachingResourceTransformer.class)); assertThat(transformers.get(1), Matchers.equalTo(mockTransformer)); + Mockito.verify(mockTransformer).setResourceUrlProvider(resourceUrlProvider); } @Test diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java index 182b7e8bb46..8aa4185ad1a 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java @@ -52,6 +52,7 @@ import org.springframework.web.bind.support.WebExchangeDataBinder; import org.springframework.web.reactive.accept.RequestedContentTypeResolver; import org.springframework.web.reactive.handler.AbstractUrlHandlerMapping; import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping; +import org.springframework.web.reactive.resource.ResourceUrlProvider; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler; @@ -267,6 +268,15 @@ public class WebFluxConfigurationSupportTests { assertNotNull(webHandler); } + @Test + public void resourceUrlProvider() throws Exception { + ApplicationContext context = loadConfig(WebFluxConfig.class); + + String name = "resourceUrlProvider"; + ResourceUrlProvider resourceUrlProvider = context.getBean(name, ResourceUrlProvider.class); + assertNotNull(resourceUrlProvider); + } + private void assertHasMessageReader(List> readers, ResolvableType type, MediaType mediaType) { assertTrue(readers.stream().anyMatch(c -> mediaType == null || c.canRead(type, mediaType)));