Polishing external contribution
See gh-29985
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -23,8 +23,10 @@ import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -43,9 +45,12 @@ class ResourceHandlerFunction implements HandlerFunction<ServerResponse> {
|
||||
|
||||
private final Resource resource;
|
||||
|
||||
private final BiConsumer<Resource, HttpHeaders> headersConsumer;
|
||||
|
||||
public ResourceHandlerFunction(Resource resource) {
|
||||
|
||||
public ResourceHandlerFunction(Resource resource, BiConsumer<Resource, HttpHeaders> headersConsumer) {
|
||||
this.resource = resource;
|
||||
this.headersConsumer = headersConsumer;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,11 +58,15 @@ class ResourceHandlerFunction implements HandlerFunction<ServerResponse> {
|
||||
public ServerResponse handle(ServerRequest request) {
|
||||
HttpMethod method = request.method();
|
||||
if (HttpMethod.GET.equals(method)) {
|
||||
return EntityResponse.fromObject(this.resource).build();
|
||||
return EntityResponse.fromObject(this.resource)
|
||||
.headers(headers -> this.headersConsumer.accept(this.resource, headers))
|
||||
.build();
|
||||
}
|
||||
else if (HttpMethod.HEAD.equals(method)) {
|
||||
Resource headResource = new HeadMethodResource(this.resource);
|
||||
return EntityResponse.fromObject(headResource).build();
|
||||
return EntityResponse.fromObject(headResource)
|
||||
.headers(headers -> this.headersConsumer.accept(this.resource, headers))
|
||||
.build();
|
||||
}
|
||||
else if (HttpMethod.OPTIONS.equals(method)) {
|
||||
return ServerResponse.ok()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@@ -28,6 +29,7 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -239,11 +241,25 @@ class RouterFunctionBuilder implements RouterFunctions.Builder {
|
||||
return add(RouterFunctions.resources(pattern, location));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouterFunctions.Builder resources(String pattern, Resource location,
|
||||
BiConsumer<Resource, HttpHeaders> headersConsumer) {
|
||||
|
||||
return add(RouterFunctions.resources(pattern, location, headersConsumer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouterFunctions.Builder resources(Function<ServerRequest, Optional<Resource>> lookupFunction) {
|
||||
return add(RouterFunctions.resources(lookupFunction));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouterFunctions.Builder resources(Function<ServerRequest, Optional<Resource>> lookupFunction,
|
||||
BiConsumer<Resource, HttpHeaders> headersConsumer) {
|
||||
|
||||
return add(RouterFunctions.resources(lookupFunction, headersConsumer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouterFunctions.Builder nest(RequestPredicate predicate,
|
||||
Consumer<RouterFunctions.Builder> builderConsumer) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@@ -30,6 +31,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
@@ -139,7 +141,26 @@ public abstract class RouterFunctions {
|
||||
* @see #resourceLookupFunction(String, Resource)
|
||||
*/
|
||||
public static RouterFunction<ServerResponse> resources(String pattern, Resource location) {
|
||||
return resources(resourceLookupFunction(pattern, location));
|
||||
return resources(resourceLookupFunction(pattern, location), (resource, httpHeaders) -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Route requests that match the given pattern to resources relative to the given root location.
|
||||
* For instance
|
||||
* <pre class="code">
|
||||
* Resource location = new FileSystemResource("public-resources/");
|
||||
* RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
|
||||
* </pre>
|
||||
* @param pattern the pattern to match
|
||||
* @param location the location directory relative to which resources should be resolved
|
||||
* @param headersConsumer provides access to the HTTP headers for served resources
|
||||
* @return a router function that routes to resources
|
||||
* @since 6.1
|
||||
* @see #resourceLookupFunction(String, Resource)
|
||||
*/
|
||||
public static RouterFunction<ServerResponse> resources(String pattern, Resource location,
|
||||
BiConsumer<Resource, HttpHeaders> headersConsumer) {
|
||||
return resources(resourceLookupFunction(pattern, location), headersConsumer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,9 +190,23 @@ public abstract class RouterFunctions {
|
||||
* @return a router function that routes to resources
|
||||
*/
|
||||
public static RouterFunction<ServerResponse> resources(Function<ServerRequest, Optional<Resource>> lookupFunction) {
|
||||
return new ResourcesRouterFunction(lookupFunction);
|
||||
return new ResourcesRouterFunction(lookupFunction, (resource, httpHeaders) -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to resources using the provided lookup function. If the lookup function provides a
|
||||
* {@link Resource} for the given request, it will be it will be exposed using a
|
||||
* {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
|
||||
* @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
|
||||
* @param headersConsumer provides access to the HTTP headers for served resources
|
||||
* @return a router function that routes to resources
|
||||
* @since 6.1
|
||||
*/
|
||||
public static RouterFunction<ServerResponse> resources(Function<ServerRequest, Optional<Resource>> lookupFunction, BiConsumer<Resource, HttpHeaders> headersConsumer) {
|
||||
return new ResourcesRouterFunction(lookupFunction, headersConsumer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes the {@link PathPatternParser} on the given {@linkplain RouterFunction router function}. This method
|
||||
* can be used to change the {@code PathPatternParser} properties from the defaults, for instance to change
|
||||
@@ -563,6 +598,21 @@ public abstract class RouterFunctions {
|
||||
*/
|
||||
Builder resources(String pattern, Resource location);
|
||||
|
||||
/**
|
||||
* Route requests that match the given pattern to resources relative to the given root location.
|
||||
* For instance
|
||||
* <pre class="code">
|
||||
* Resource location = new FileSystemResource("public-resources/");
|
||||
* RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
|
||||
* </pre>
|
||||
* @param pattern the pattern to match
|
||||
* @param location the location directory relative to which resources should be resolved
|
||||
* @param headersConsumer provides access to the HTTP headers for served resources
|
||||
* @return this builder
|
||||
* @since 6.1
|
||||
*/
|
||||
Builder resources(String pattern, Resource location, BiConsumer<Resource, HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Route to resources using the provided lookup function. If the lookup function provides a
|
||||
* {@link Resource} for the given request, it will be it will be exposed using a
|
||||
@@ -572,6 +622,17 @@ public abstract class RouterFunctions {
|
||||
*/
|
||||
Builder resources(Function<ServerRequest, Optional<Resource>> lookupFunction);
|
||||
|
||||
/**
|
||||
* Route to resources using the provided lookup function. If the lookup function provides a
|
||||
* {@link Resource} for the given request, it will be it will be exposed using a
|
||||
* {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
|
||||
* @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
|
||||
* @param headersConsumer provides access to the HTTP headers for served resources
|
||||
* @return this builder
|
||||
* @since 6.1
|
||||
*/
|
||||
Builder resources(Function<ServerRequest, Optional<Resource>> lookupFunction, BiConsumer<Resource, HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Route to the supplied router function if the given request predicate applies. This method
|
||||
* can be used to create <strong>nested routes</strong>, where a group of routes share a
|
||||
@@ -1059,14 +1120,20 @@ public abstract class RouterFunctions {
|
||||
|
||||
private final Function<ServerRequest, Optional<Resource>> lookupFunction;
|
||||
|
||||
public ResourcesRouterFunction(Function<ServerRequest, Optional<Resource>> lookupFunction) {
|
||||
private final BiConsumer<Resource, HttpHeaders> headersConsumer;
|
||||
|
||||
|
||||
public ResourcesRouterFunction(Function<ServerRequest, Optional<Resource>> lookupFunction,
|
||||
BiConsumer<Resource, HttpHeaders> headersConsumer) {
|
||||
Assert.notNull(lookupFunction, "Function must not be null");
|
||||
Assert.notNull(headersConsumer, "HeadersConsumer must not be null");
|
||||
this.lookupFunction = lookupFunction;
|
||||
this.headersConsumer = headersConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<HandlerFunction<ServerResponse>> route(ServerRequest request) {
|
||||
return this.lookupFunction.apply(request).map(ResourceHandlerFunction::new);
|
||||
return this.lookupFunction.apply(request).map(resource -> new ResourceHandlerFunction(resource, this.headersConsumer));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -50,7 +50,7 @@ public class ResourceHandlerFunctionTests {
|
||||
|
||||
private final Resource resource = new ClassPathResource("response.txt", getClass());
|
||||
|
||||
private final ResourceHandlerFunction handlerFunction = new ResourceHandlerFunction(this.resource);
|
||||
private final ResourceHandlerFunction handlerFunction = new ResourceHandlerFunction(this.resource, (r, h) -> {});
|
||||
|
||||
private ServerResponse.Context context;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.web.servlet.function;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -27,6 +28,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -118,6 +120,23 @@ class RouterFunctionBuilderTests {
|
||||
assertThat(responseStatus).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resourcesCaching() {
|
||||
Resource resource = new ClassPathResource("/org/springframework/web/servlet/function/");
|
||||
assertThat(resource.exists()).isTrue();
|
||||
|
||||
RouterFunction<ServerResponse> route = RouterFunctions.route()
|
||||
.resources("/resources/**", resource, (r, headers) -> headers.setCacheControl(CacheControl.maxAge(Duration.ofSeconds(60))))
|
||||
.build();
|
||||
|
||||
ServerRequest resourceRequest = initRequest("GET", "/resources/response.txt");
|
||||
|
||||
Optional<String> responseCacheControl = route.route(resourceRequest)
|
||||
.map(handlerFunction -> handle(handlerFunction, resourceRequest))
|
||||
.map(response -> response.headers().getCacheControl());
|
||||
assertThat(responseCacheControl).contains("max-age=60");
|
||||
}
|
||||
|
||||
@Test
|
||||
void nest() {
|
||||
RouterFunction<ServerResponse> route = RouterFunctions.route()
|
||||
|
||||
Reference in New Issue
Block a user