From 0bbb7704b517f0721ee1ac810b854fbc3f30697f Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Thu, 17 Jul 2014 18:04:43 -0400 Subject: [PATCH] Add propagateQueryParams property to RedirectView This change makes it possible to configure RedirectView such that the query string of the current request is added to the target URL. This change is preparation for SPR-11543. --- .../web/servlet/view/RedirectView.java | 64 +++++++++++++++++-- .../web/servlet/view/RedirectViewTests.java | 13 ++++ 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/RedirectView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/RedirectView.java index 1db7aafb831..8a74f778afc 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/RedirectView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/RedirectView.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -53,7 +53,7 @@ import org.springframework.web.util.UriUtils; import org.springframework.web.util.WebUtils; /** - *

View that redirects to an absolute, context relative, or current request + * View that redirects to an absolute, context relative, or current request * relative URL. The URL may be a URI template in which case the URI template * variables will be replaced with values available in the model. By default * all primitive model attributes (or collections thereof) are exposed as HTTP @@ -105,6 +105,8 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView { private boolean expandUriTemplateVariables = true; + private boolean propagateQueryParams = false; + /** * Constructor for use as a bean. @@ -235,6 +237,24 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView { this.expandUriTemplateVariables = expandUriTemplateVariables; } + /** + * When set to {@code true} the query string of the current URL is appended + * and thus propagated through to the redirected URL. + *

Defaults to {@code false}. + * @since 4.1 + */ + public void setPropagateQueryParams(boolean propagateQueryParams) { + this.propagateQueryParams = propagateQueryParams; + } + + /** + * Whether to propagate the query params of the current URL. + * @since 4.1 + */ + public boolean isPropagateQueryProperties() { + return this.propagateQueryParams; + } + /** * Returns "true" indicating this view performs a redirect. */ @@ -307,6 +327,9 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView { Map variables = getCurrentRequestUriVariables(request); targetUrl = replaceUriTemplateVariables(targetUrl.toString(), model, variables, enc); } + if (isPropagateQueryProperties()) { + appendCurrentQueryParams(targetUrl, request); + } if (this.exposeModelAttributes) { appendQueryProperties(targetUrl, model, enc); } @@ -347,11 +370,44 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView { @SuppressWarnings("unchecked") private Map getCurrentRequestUriVariables(HttpServletRequest request) { - Map uriVars = - (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + String name = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE; + Map uriVars = (Map) request.getAttribute(name); return (uriVars != null) ? uriVars : Collections. emptyMap(); } + /** + * Append the query string of the current request to the target redirect URL. + * @param targetUrl the StringBuilder to append the properties to + * @param request the current request + * @since 4.1 + */ + protected void appendCurrentQueryParams(StringBuilder targetUrl, HttpServletRequest request) { + + String query = request.getQueryString(); + if (StringUtils.hasText(query)) { + + // Extract anchor fragment, if any. + String fragment = null; + int anchorIndex = targetUrl.indexOf("#"); + if (anchorIndex > -1) { + fragment = targetUrl.substring(anchorIndex); + targetUrl.delete(anchorIndex, targetUrl.length()); + } + + if (targetUrl.toString().indexOf('?') < 0) { + targetUrl.append('?').append(query); + } + else { + targetUrl.append('&').append(query); + } + + // Append anchor fragment, if any, to end of URL. + if (fragment != null) { + targetUrl.append(fragment); + } + } + } + /** * Append query properties to the redirect URL. * Stringifies, URL-encodes and formats model attributes as query properties. diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/RedirectViewTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/RedirectViewTests.java index 2e800c9d5b8..3b142aca481 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/RedirectViewTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/RedirectViewTests.java @@ -325,6 +325,19 @@ public class RedirectViewTests { doTest(model, url, false, expectedUrlForEncoding); } + @Test + public void propagateQueryParams() throws Exception { + RedirectView rv = new RedirectView(); + rv.setPropagateQueryParams(true); + rv.setUrl("http://url.somewhere.com?foo=bar#bazz"); + MockHttpServletRequest request = createRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + request.setQueryString("a=b&c=d"); + rv.render(new HashMap(), request, response); + assertEquals(302, response.getStatus()); + assertEquals("http://url.somewhere.com?foo=bar&a=b&c=d#bazz", response.getHeader("Location")); + } + private void doTest(Map map, String url, boolean contextRelative, String expectedUrlForEncoding) throws Exception { doTest(map, url, contextRelative, true, expectedUrlForEncoding);