Fix issue with "redirect:" when a media type is present

Issue: SPR-15291
This commit is contained in:
Rossen Stoyanchev 2017-05-24 16:28:17 -04:00
parent 109746a03b
commit 718162b8c4
4 changed files with 45 additions and 7 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -169,6 +169,11 @@ public class RedirectView extends AbstractUrlBasedView {
} }
@Override
public boolean isRedirectView() {
return true;
}
@Override @Override
public boolean checkResourceExists(Locale locale) throws Exception { public boolean checkResourceExists(Locale locale) throws Exception {
return true; return true;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -47,6 +47,13 @@ public interface View {
*/ */
List<MediaType> getSupportedMediaTypes(); List<MediaType> getSupportedMediaTypes();
/**
* Whether this View does rendering by performing a redirect.
*/
default boolean isRedirectView() {
return false;
}
/** /**
* Render the view based on the given {@link HandlerResult}. Implementations * Render the view based on the given {@link HandlerResult}. Implementations
* can access and use the model or only a specific attribute in it. * can access and use the model or only a specific attribute in it.

View File

@ -310,6 +310,12 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
private Mono<? extends Void> render(List<View> views, Map<String, Object> model, private Mono<? extends Void> render(List<View> views, Map<String, Object> model,
ServerWebExchange exchange) { ServerWebExchange exchange) {
for (View view : views) {
if (view.isRedirectView()) {
return view.render(model, null, exchange);
}
}
List<MediaType> mediaTypes = getMediaTypes(views); List<MediaType> mediaTypes = getMediaTypes(views);
MediaType bestMediaType = selectMediaType(exchange, () -> mediaTypes); MediaType bestMediaType = selectMediaType(exchange, () -> mediaTypes);
if (bestMediaType != null) { if (bestMediaType != null) {

View File

@ -33,6 +33,7 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import rx.Completable; import rx.Completable;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
@ -42,6 +43,7 @@ import org.springframework.core.io.buffer.support.DataBufferTestUtils;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange; import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;
import org.springframework.ui.ConcurrentModel; import org.springframework.ui.ConcurrentModel;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -194,11 +196,10 @@ public class ViewResolutionResultHandlerTests {
@Test @Test
public void handleWithMultipleResolvers() throws Exception { public void handleWithMultipleResolvers() throws Exception {
Object returnValue = "profile"; testHandle("/account",
MethodParameter returnType = on(Handler.class).annotNotPresent(ModelAttribute.class).resolveReturnType(String.class); on(Handler.class).annotNotPresent(ModelAttribute.class).resolveReturnType(String.class),
ViewResolver[] resolvers = {new TestViewResolver("account"), new TestViewResolver("profile")}; "profile", "profile: {id=123}",
new TestViewResolver("account"), new TestViewResolver("profile"));
testHandle("/account", returnType, returnValue, "profile: {id=123}", resolvers);
} }
@Test @Test
@ -280,6 +281,25 @@ public class ViewResolutionResultHandlerTests {
.verify(); .verify();
} }
@Test // SPR-15291
public void contentNegotiationWithRedirect() throws Exception {
HandlerResult handlerResult = new HandlerResult(new Object(), "redirect:/",
on(Handler.class).annotNotPresent(ModelAttribute.class).resolveReturnType(String.class),
this.bindingContext);
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setApplicationContext(new StaticApplicationContext());
ViewResolutionResultHandler resultHandler = resultHandler(viewResolver);
MockServerWebExchange exchange = get("/account").accept(APPLICATION_JSON).toExchange();
resultHandler.handleResult(exchange, handlerResult).block(Duration.ZERO);
MockServerHttpResponse response = exchange.getResponse();
assertEquals(303, response.getStatusCode().value());
assertEquals("/", response.getHeaders().getLocation().toString());
}
private ViewResolutionResultHandler resultHandler(ViewResolver... resolvers) { private ViewResolutionResultHandler resultHandler(ViewResolver... resolvers) {
return resultHandler(Collections.emptyList(), resolvers); return resultHandler(Collections.emptyList(), resolvers);