Set default view content-type with WebFlux fn

With this commit, the default content-type defined by the
view (usually "text/html;charset=UTF-8" defined in AbstractView)
is used if any, when none is defined in the response headers.

Issue: SPR-16247
This commit is contained in:
sdeleuze 2017-12-19 10:45:07 +01:00
parent e3e4f37222
commit 99cbfd32c3
2 changed files with 45 additions and 2 deletions

View File

@ -20,6 +20,7 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -177,7 +178,7 @@ class DefaultRenderingResponseBuilder implements RenderingResponse.Builder {
public Mono<Void> writeTo(ServerWebExchange exchange, Context context) { public Mono<Void> writeTo(ServerWebExchange exchange, Context context) {
ServerHttpResponse response = exchange.getResponse(); ServerHttpResponse response = exchange.getResponse();
writeStatusAndHeaders(response); writeStatusAndHeaders(response);
MediaType contentType = exchange.getResponse().getHeaders().getContentType(); MediaType responseContentType = exchange.getResponse().getHeaders().getContentType();
Locale locale = LocaleContextHolder.getLocale(exchange.getLocaleContext()); Locale locale = LocaleContextHolder.getLocale(exchange.getLocaleContext());
Stream<ViewResolver> viewResolverStream = context.viewResolvers().stream(); Stream<ViewResolver> viewResolverStream = context.viewResolvers().stream();
@ -186,7 +187,11 @@ class DefaultRenderingResponseBuilder implements RenderingResponse.Builder {
.next() .next()
.switchIfEmpty(Mono.error(new IllegalArgumentException("Could not resolve view with name '" + .switchIfEmpty(Mono.error(new IllegalArgumentException("Could not resolve view with name '" +
name() +"'"))) name() +"'")))
.flatMap(view -> view.render(model(), contentType, exchange)); .flatMap(view -> {
List<MediaType> mediaTypes = view.getSupportedMediaTypes();
MediaType contentType = (responseContentType == null && !mediaTypes.isEmpty() ? mediaTypes.get(0) : responseContentType);
return view.render(model(), contentType, exchange);
});
} }
} }

View File

@ -28,14 +28,19 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseCookie;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.web.test.server.MockServerWebExchange; import org.springframework.mock.web.test.server.MockServerWebExchange;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.result.view.AbstractView;
import org.springframework.web.reactive.result.view.View; import org.springframework.web.reactive.result.view.View;
import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.reactive.result.view.ViewResolverSupport;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
/** /**
@ -143,4 +148,37 @@ public class DefaultRenderingResponseTests {
.verify(); .verify();
} }
@Test
public void defaultContentType() throws Exception {
Mono<RenderingResponse> result = RenderingResponse.create("view").build();
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://localhost"));
TestView view = new TestView();
ViewResolver viewResolver = mock(ViewResolver.class);
when(viewResolver.resolveViewName(any(), any())).thenReturn(Mono.just(view));
List<ViewResolver> viewResolvers = new ArrayList<>();
viewResolvers.add(viewResolver);
ServerResponse.Context context = mock(ServerResponse.Context.class);
when(context.viewResolvers()).thenReturn(viewResolvers);
StepVerifier.create(result.flatMap(response -> response.writeTo(exchange, context)))
.verifyComplete();
assertEquals(ViewResolverSupport.DEFAULT_CONTENT_TYPE, exchange.getResponse().getHeaders().getContentType());
}
private static class TestView extends AbstractView {
@Override
protected Mono<Void> renderInternal(Map<String, Object> renderAttributes,
MediaType contentType, ServerWebExchange exchange) {
return Mono.empty();
}
}
} }