Browse Source

Polish RedirectView

Issue: SPR-14534
pull/1253/head
Sebastien Deleuze 9 years ago
parent
commit
300f2cd2dd
  1. 161
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/RedirectView.java
  2. 1
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/UrlBasedViewResolver.java
  3. 14
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/RedirectViewTests.java
  4. 2
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/UrlBasedViewResolverTests.java

161
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/RedirectView.java

@ -45,8 +45,9 @@ import org.springframework.web.util.UriUtils;
* available in the model. * available in the model.
* *
* <p>A URL for this view is supposed to be a HTTP redirect which does the redirect via * <p>A URL for this view is supposed to be a HTTP redirect which does the redirect via
* sending an {@link HttpStatus#SEE_OTHER} code. If HTTP 1.0 compatibility is needed, * sending a {@literal 3xx} status code. By default {@link HttpStatus#SEE_OTHER} is used.
* {@link HttpStatus#FOUND} code can be set via {@link #setStatusCode(HttpStatus)}. * If HTTP 1.0 compatibility is needed, {@link HttpStatus#FOUND} code can be set via
* {@link #setStatusCode(HttpStatus)}.
* *
* <p>Note that the default value for the "contextRelative" flag is true. * <p>Note that the default value for the "contextRelative" flag is true.
* With the flag on, URLs starting with "/" are considered relative to the web application * With the flag on, URLs starting with "/" are considered relative to the web application
@ -54,7 +55,6 @@ import org.springframework.web.util.UriUtils;
* root. * root.
* *
* @author Sebastien Deleuze * @author Sebastien Deleuze
* @see #setContextRelative
* @since 5.0 * @since 5.0
*/ */
public class RedirectView extends AbstractUrlBasedView { public class RedirectView extends AbstractUrlBasedView {
@ -66,49 +66,70 @@ public class RedirectView extends AbstractUrlBasedView {
private HttpStatus statusCode = HttpStatus.SEE_OTHER; private HttpStatus statusCode = HttpStatus.SEE_OTHER;
private boolean propagateQueryParams = false; private boolean propagateQuery = false;
private String[] hosts; private String[] hosts;
/** /**
* Create a new {@code RedirectView} with the given redirect URL. * Constructor for use as a bean.
* */
* @see #builder(String) public RedirectView() {
}
/**
* Create a new {@code RedirectView} with the given URL and the {@link HttpStatus#SEE_OTHER}
* status code which is the correct code for HTTP 1.1 clients.
*/ */
public RedirectView(String redirectUrl) { public RedirectView(String redirectUrl) {
super(redirectUrl); super(redirectUrl);
} }
/** /**
* Return a builder for a {@code RedirectView}. * Create a new {@code RedirectView} with the given redirect URL ans status code. Most
* frequently used ones are:
* <ul>
* <li>{@link HttpStatus#SEE_OTHER} : temporary redirect for HTTP 1.1 compatible clients</li>
* <li>{@link HttpStatus#FOUND} : temporary redirect for HTTP 1.0 compatible clients</li>
* <li>{@link HttpStatus#MOVED_PERMANENTLY} : permanent redirect</li>
* </ul>
*/ */
public static Builder builder(String redirectUrl) { public RedirectView(String redirectUrl, HttpStatus statusCode) {
return new BuilderImpl(redirectUrl); super(redirectUrl);
setStatusCode(statusCode);
} }
/** /**
* Set whether to interpret a given URL that starts with a slash ("/") * Set whether to interpret a given URL that starts with a slash ("/")
* as relative to the current context path. * as relative to the current context path ({@code true}, the default) or to
* <p>Default is "true": the context path will be * the web server root ({@code false}).
* prepended to the URL in such a case. If "false", an URL that starts
* with a slash will be interpreted as absolute, i.e. taken as-is.
*/ */
public void setContextRelative(boolean contextRelative) { public void setContextRelative(boolean contextRelative) {
this.contextRelative = contextRelative; this.contextRelative = contextRelative;
} }
/** /**
* Set a customized redirect status code to be used for a redirect. Default is * Return whether to interpret a given URL that starts with a slash ("/")
* {@link HttpStatus#SEE_OTHER} which is the correct code for HTTP 1.1 * as relative to the current context path ("true") or to the web server
* clients. This setter can be used to configure {@link HttpStatus#FOUND} * root ("false").
* if HTTP 1.0 clients need to be supported, or any other {@literal 3xx} * @return
* status code. */
public boolean isContextRelative() {
return contextRelative;
}
/**
* Set the redirect status code. Most frequently used ones are:
* <ul>
* <li>{@link HttpStatus#SEE_OTHER} : temporary redirect for HTTP 1.1 compatible clients</li>
* <li>{@link HttpStatus#FOUND} : temporary redirect for HTTP 1.0 compatible clients</li>
* <li>{@link HttpStatus#MOVED_PERMANENTLY} : permanent redirect</li>
* </ul>
*/ */
public void setStatusCode(HttpStatus statusCode) { public void setStatusCode(HttpStatus statusCode) {
Assert.notNull(statusCode); Assert.notNull(statusCode, "HttpStatus must not be null");
Assert.isTrue(statusCode.is3xxRedirection(), "HttpStatus must be a redirection (3xx status code)");
this.statusCode = statusCode; this.statusCode = statusCode;
} }
@ -120,12 +141,19 @@ public class RedirectView extends AbstractUrlBasedView {
} }
/** /**
* When set to {@code true} the query string of the current URL is appended * Set whether to append the query string of the current URL to the redirected URL
* and thus propagated through to the redirected URL. * ({@code true}) or not ({@code false}, the default).
* <p>Defaults to {@code false}.
*/ */
public void setPropagateQueryParams(boolean propagateQueryParams) { public void setPropagateQuery(boolean propagateQuery) {
this.propagateQueryParams = propagateQueryParams; this.propagateQuery = propagateQuery;
}
/**
* Return whether the query string of the current URL is appended to the redirected URL
* ({@code true}) or not ({@code false}).
*/
public boolean isPropagateQuery() {
return propagateQuery;
} }
/** /**
@ -141,6 +169,13 @@ public class RedirectView extends AbstractUrlBasedView {
this.hosts = hosts; this.hosts = hosts;
} }
/**
* Return the configured application hosts.
*/
public String[] getHosts() {
return this.hosts;
}
/** /**
* Convert model to request parameters and redirect to the given URL. * Convert model to request parameters and redirect to the given URL.
* @see #sendRedirect * @see #sendRedirect
@ -173,7 +208,7 @@ public class RedirectView extends AbstractUrlBasedView {
Map<String, String> variables = getCurrentRequestUriVariables(exchange); Map<String, String> variables = getCurrentRequestUriVariables(exchange);
targetUrl = replaceUriTemplateVariables(targetUrl.toString(), model, variables, charset); targetUrl = replaceUriTemplateVariables(targetUrl.toString(), model, variables, charset);
} }
if (this.propagateQueryParams) { if (this.propagateQuery) {
appendCurrentQueryParams(targetUrl, request); appendCurrentQueryParams(targetUrl, request);
} }
@ -292,74 +327,12 @@ public class RedirectView extends AbstractUrlBasedView {
return true; return true;
} }
public interface Builder { @Override
public void afterPropertiesSet() throws Exception {
/** super.afterPropertiesSet();
* @see RedirectView#setContextRelative(boolean) if (getStatusCode() == null) {
*/ throw new IllegalArgumentException("Property 'statusCode' is required");
Builder contextRelative(boolean contextRelative);
/**
* @see RedirectView#setStatusCode(HttpStatus)
*/
Builder statusCode(HttpStatus statusCode);
/**
* @see RedirectView#setPropagateQueryParams(boolean)
*/
Builder propagateQueryParams(boolean propagateQueryParams);
/**
* @see RedirectView#setHosts(String...)
*/
Builder hosts(String... hosts);
/**
* Build the redirect view.
*/
RedirectView build();
}
private static class BuilderImpl implements Builder {
private final RedirectView view;
public BuilderImpl(String redirectUrl) {
this.view = new RedirectView(redirectUrl);
}
@Override
public Builder contextRelative(boolean contextRelative) {
this.view.setContextRelative(contextRelative);
return this;
}
@Override
public Builder statusCode(HttpStatus statusCode) {
this.view.setStatusCode(statusCode);
return this;
}
@Override
public Builder propagateQueryParams(boolean propagateQueryParams) {
this.view.setPropagateQueryParams(propagateQueryParams);
return this;
}
@Override
public Builder hosts(String... hosts) {
this.view.setHosts(hosts);
return this;
}
@Override
public RedirectView build() {
return this.view;
} }
} }
} }

1
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/view/UrlBasedViewResolver.java

@ -53,6 +53,7 @@ import org.springframework.util.PatternMatchUtils;
* <p>Note: This class does not support localized resolution, i.e. resolving * <p>Note: This class does not support localized resolution, i.e. resolving
* a symbolic view name to different resources depending on the current locale. * a symbolic view name to different resources depending on the current locale.
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Sebastien Deleuze
* @since 5.0 * @since 5.0
*/ */
public class UrlBasedViewResolver extends ViewResolverSupport implements ViewResolver, InitializingBean { public class UrlBasedViewResolver extends ViewResolverSupport implements ViewResolver, InitializingBean {

14
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/RedirectViewTests.java

@ -76,13 +76,11 @@ public class RedirectViewTests {
@Test @Test
public void customStatusCode() { public void customStatusCode() {
RedirectView view = RedirectView String url = "http://url.somewhere.com";
.builder("http://url.somewhere.com") RedirectView view = new RedirectView(url, HttpStatus.FOUND);
.statusCode(HttpStatus.FOUND)
.build();
view.render(new HashMap<>(), MediaType.TEXT_HTML, exchange); view.render(new HashMap<>(), MediaType.TEXT_HTML, exchange);
assertEquals(HttpStatus.FOUND, response.getStatusCode()); assertEquals(HttpStatus.FOUND, response.getStatusCode());
assertEquals(URI.create("http://url.somewhere.com"), response.getHeaders().getLocation()); assertEquals(URI.create(url), response.getHeaders().getLocation());
} }
@Test @Test
@ -137,10 +135,8 @@ public class RedirectViewTests {
@Test @Test
public void propagateQueryParams() throws Exception { public void propagateQueryParams() throws Exception {
RedirectView view = RedirectView RedirectView view = new RedirectView("http://url.somewhere.com?foo=bar#bazz");
.builder("http://url.somewhere.com?foo=bar#bazz") view.setPropagateQuery(true);
.propagateQueryParams(true)
.build();
request.setUri(URI.create("http://url.somewhere.com?a=b&c=d")); request.setUri(URI.create("http://url.somewhere.com?a=b&c=d"));
view.render(new HashMap<>(), MediaType.TEXT_HTML, exchange); view.render(new HashMap<>(), MediaType.TEXT_HTML, exchange);
assertEquals(HttpStatus.SEE_OTHER, response.getStatusCode()); assertEquals(HttpStatus.SEE_OTHER, response.getStatusCode());

2
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/view/UrlBasedViewResolverTests.java

@ -77,7 +77,7 @@ public class UrlBasedViewResolverTests {
@Test @Test
public void customizedRedirectView() throws Exception { public void customizedRedirectView() throws Exception {
resolver.setRedirectViewProvider(url -> RedirectView.builder(url).statusCode(HttpStatus.FOUND).build()); resolver.setRedirectViewProvider(url -> new RedirectView(url, HttpStatus.FOUND));
Mono<View> mono = resolver.resolveViewName("redirect:foo", Locale.US); Mono<View> mono = resolver.resolveViewName("redirect:foo", Locale.US);
assertNotNull(mono.block()); assertNotNull(mono.block());
StepVerifier.create(mono) StepVerifier.create(mono)

Loading…
Cancel
Save