diff --git a/core/src/main/java/org/apache/struts2/dispatcher/ServletActionRedirectResult.java b/core/src/main/java/org/apache/struts2/dispatcher/ServletActionRedirectResult.java index 44baf6878..e4f7f9c93 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/ServletActionRedirectResult.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/ServletActionRedirectResult.java @@ -21,22 +21,15 @@ package org.apache.struts2.dispatcher; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.struts2.dispatcher.mapper.ActionMapper; -import org.apache.struts2.dispatcher.mapper.ActionMapping; -import org.apache.struts2.views.util.UrlHelper; - import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.config.entities.ResultConfig; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; -import com.opensymphony.xwork2.util.reflection.ReflectionException; import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler; +import org.apache.struts2.dispatcher.mapper.ActionMapper; +import org.apache.struts2.dispatcher.mapper.ActionMapping; + +import java.util.Arrays; +import java.util.List; /** * @@ -137,15 +130,20 @@ public class ServletActionRedirectResult extends ServletRedirectResult implement } public ServletActionRedirectResult(String actionName) { - this(null, actionName, null); + this(null, actionName, null, null); } public ServletActionRedirectResult(String actionName, String method) { - this(null, actionName, method); + this(null, actionName, method, null); } + public ServletActionRedirectResult(String namespace, String actionName, String method) { - super(null); + this(namespace, actionName, method, null); + } + + public ServletActionRedirectResult(String namespace, String actionName, String method, String anchor) { + super(null, anchor); this.namespace = namespace; this.actionName = actionName; this.method = method; @@ -206,6 +204,6 @@ public class ServletActionRedirectResult extends ServletRedirectResult implement protected List getProhibitedResultParams() { return Arrays.asList(new String[]{ DEFAULT_PARAM, "namespace", "method", "encode", "parse", "location", - "prependServletContext", "supressEmptyParameters"}); + "prependServletContext", "supressEmptyParameters", "anchor"}); } } diff --git a/core/src/main/java/org/apache/struts2/dispatcher/ServletRedirectResult.java b/core/src/main/java/org/apache/struts2/dispatcher/ServletRedirectResult.java index b509cf1b8..463638cef 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/ServletRedirectResult.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/ServletRedirectResult.java @@ -21,15 +21,6 @@ package org.apache.struts2.dispatcher; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import static javax.servlet.http.HttpServletResponse.*; - -import org.apache.struts2.ServletActionContext; -import org.apache.struts2.views.util.UrlHelper; -import org.apache.struts2.dispatcher.mapper.ActionMapper; -import org.apache.struts2.dispatcher.mapper.ActionMapping; - import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.config.entities.ResultConfig; @@ -38,13 +29,21 @@ import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import com.opensymphony.xwork2.util.reflection.ReflectionException; import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler; +import org.apache.struts2.ServletActionContext; +import org.apache.struts2.dispatcher.mapper.ActionMapper; +import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.apache.struts2.views.util.UrlHelper; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Map; -import java.util.LinkedHashMap; -import java.util.Iterator; -import java.util.List; import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static javax.servlet.http.HttpServletResponse.SC_FOUND; /** @@ -72,6 +71,8 @@ import java.util.Arrays; *
  • parse - true by default. If set to false, the location param will * not be parsed for Ognl expressions.
  • * + *
  • anchor - optional, you can specify an anchor for result.
  • + * * * *

    @@ -86,6 +87,7 @@ import java.util.Arrays; * <result name="success" type="redirect"> * <param name="location">foo.jsp</param> * <param name="parse">false</param> + * <param name="anchor">FRAGMENT</param> * </result> * * @@ -105,13 +107,20 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec protected boolean supressEmptyParameters = false; protected Map requestParameters = new LinkedHashMap(); + + protected String anchor; public ServletRedirectResult() { super(); } public ServletRedirectResult(String location) { + this(location, null); + } + + public ServletRedirectResult(String location, String anchor) { super(location); + this.anchor = anchor; } @Inject @@ -123,6 +132,14 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec this.statusCode = code; } + /** + * Set the optional anchor value. + * @param anchor + */ + public void setAnchor(String anchor) { + this.anchor = anchor; + } + /** * Sets whether or not to prepend the servlet context path to the redirected URL. * @@ -132,6 +149,14 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec public void setPrependServletContext(boolean prependServletContext) { this.prependServletContext = prependServletContext; } + + public void execute(ActionInvocation invocation) throws Exception { + if (anchor != null) { + anchor = conditionalParse(anchor, invocation); + } + + super.execute(invocation); + } /** * Redirects to the location specified by calling {@link HttpServletResponse#sendRedirect(String)}. @@ -187,6 +212,11 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec StringBuilder tmpLocation = new StringBuilder(finalLocation); UrlHelper.buildParametersString(requestParameters, tmpLocation, "&"); + // add the anchor + if (anchor != null) { + tmpLocation.append('#').append(anchor); + } + finalLocation = response.encodeRedirectURL(tmpLocation.toString()); } @@ -200,7 +230,7 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec protected List getProhibitedResultParams() { return Arrays.asList(new String[]{ DEFAULT_PARAM, "namespace", "method", "encode", "parse", "location", - "prependServletContext", "supressEmptyParameters"}); + "prependServletContext", "supressEmptyParameters", "anchor"}); } diff --git a/core/src/test/java/org/apache/struts2/dispatcher/ServletActionRedirectResultTest.java b/core/src/test/java/org/apache/struts2/dispatcher/ServletActionRedirectResultTest.java index 6ac4595b3..2fd6eb512 100644 --- a/core/src/test/java/org/apache/struts2/dispatcher/ServletActionRedirectResultTest.java +++ b/core/src/test/java/org/apache/struts2/dispatcher/ServletActionRedirectResultTest.java @@ -31,8 +31,6 @@ import com.opensymphony.xwork2.util.ValueStack; import org.apache.struts2.ServletActionContext; import org.apache.struts2.StrutsTestCase; import org.apache.struts2.dispatcher.mapper.ActionMapper; -import static org.easymock.EasyMock.createControl; -import static org.easymock.EasyMock.expect; import org.easymock.IMocksControl; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -40,6 +38,9 @@ import org.springframework.mock.web.MockHttpServletResponse; import java.util.HashMap; import java.util.Map; +import static org.easymock.EasyMock.createControl; +import static org.easymock.EasyMock.expect; + /** * @version $Date$ $Id$ @@ -59,6 +60,7 @@ public class ServletActionRedirectResultTest extends StrutsTestCase { .addParam("param1", "${#value1}") .addParam("param2", "${#value2}") .addParam("param3", "${#value3}") + .addParam("anchor", "${#fragment}") .build(); @@ -86,6 +88,7 @@ public class ServletActionRedirectResultTest extends StrutsTestCase { result.setParse(true); result.setEncode(false); result.setPrependServletContext(false); + result.setAnchor("fragment"); IMocksControl control = createControl(); ActionProxy mockActionProxy = control.createMock(ActionProxy.class); @@ -99,7 +102,7 @@ public class ServletActionRedirectResultTest extends StrutsTestCase { control.replay(); result.setActionMapper(container.getInstance(ActionMapper.class)); result.execute(mockInvocation); - assertEquals("/myNamespace/myAction.action?param1=value+1¶m2=value+2¶m3=value+3", res.getRedirectedUrl()); + assertEquals("/myNamespace/myAction.action?param1=value+1¶m2=value+2¶m3=value+3#fragment", res.getRedirectedUrl()); control.verify(); } @@ -117,6 +120,7 @@ public class ServletActionRedirectResultTest extends StrutsTestCase { .addParam("param1", "value 1") .addParam("param2", "value 2") .addParam("param3", "value 3") + .addParam("anchor", "fragment") .build(); ActionContext context = ActionContext.getContext(); @@ -138,6 +142,7 @@ public class ServletActionRedirectResultTest extends StrutsTestCase { result.setParse(false); result.setEncode(false); result.setPrependServletContext(false); + result.setAnchor("fragment"); IMocksControl control = createControl(); ActionProxy mockActionProxy = control.createMock(ActionProxy.class); @@ -150,7 +155,7 @@ public class ServletActionRedirectResultTest extends StrutsTestCase { control.replay(); result.setActionMapper(container.getInstance(ActionMapper.class)); result.execute(mockInvocation); - assertEquals("/myNamespace/myAction.action?param1=value+1¶m2=value+2¶m3=value+3", res.getRedirectedUrl()); + assertEquals("/myNamespace/myAction.action?param1=value+1¶m2=value+2¶m3=value+3#fragment", res.getRedirectedUrl()); control.verify(); } @@ -168,10 +173,12 @@ public class ServletActionRedirectResultTest extends StrutsTestCase { .addParam("param1", "value 1") .addParam("param2", "value 2") .addParam("param3", "value 3") + .addParam("anchor", "fragment") .build(); ObjectFactory factory = container.getInstance(ObjectFactory.class); ServletActionRedirectResult result = (ServletActionRedirectResult) factory.buildResult(resultConfig, new HashMap()); assertNotNull(result); } + } diff --git a/core/src/test/java/org/apache/struts2/dispatcher/ServletRedirectResultTest.java b/core/src/test/java/org/apache/struts2/dispatcher/ServletRedirectResultTest.java index 0183546bc..9e88c1b3f 100644 --- a/core/src/test/java/org/apache/struts2/dispatcher/ServletRedirectResultTest.java +++ b/core/src/test/java/org/apache/struts2/dispatcher/ServletRedirectResultTest.java @@ -94,6 +94,21 @@ public class ServletRedirectResultTest extends StrutsTestCase implements StrutsS assertEquals("/context/bar/foo.jsp", writer.toString()); } + public void testAbsoluteRedirectAnchor() { + view.setLocation("/bar/foo.jsp"); + view.setAnchor("fragment"); + responseMock.expectAndReturn("encodeRedirectURL", "/context/bar/foo.jsp#fragment", "/context/bar/foo.jsp#fragment"); + responseMock.expect("sendRedirect", C.args(C.eq("/context/bar/foo.jsp#fragment"))); + + try { + view.execute(ai); + requestMock.verify(); + responseMock.verify(); + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } public void testPrependServletContextFalse() { view.setLocation("/bar/foo.jsp"); view.setPrependServletContext(false); @@ -172,6 +187,7 @@ public class ServletRedirectResultTest extends StrutsTestCase implements StrutsS result.setParse(false); result.setEncode(false); result.setPrependServletContext(false); + result.setAnchor("fragment"); IMocksControl control = createControl(); ActionProxy mockActionProxy = control.createMock(ActionProxy.class); @@ -184,7 +200,7 @@ public class ServletRedirectResultTest extends StrutsTestCase implements StrutsS control.replay(); result.setActionMapper(container.getInstance(ActionMapper.class)); result.execute(mockInvocation); - assertEquals("/myNamespace/myAction.action?param1=value+1¶m2=value+2¶m3=value+3", res.getRedirectedUrl()); + assertEquals("/myNamespace/myAction.action?param1=value+1¶m2=value+2¶m3=value+3#fragment", res.getRedirectedUrl()); control.verify(); }