Vita Rara: A Life Uncommon

Post and Redirect in Struts 2


Categories: | |

Redirecting a user of a web application after submitting an HTTP POST is a common pattern. A common use case is to redirect to a display page after a user has created something, such as a purchase order or sales order.

This post and redirect pattern is supported by Struts 2. The means of doing this wasn't obvious to me, but some reading and searching turned up the answer. There are some examples around for doing a redirect using static parameters, but that doesn't help when you want to redirect someone say to display the order they just placed on your website.

Redirects in Struts 2 can use static or dynamic parameters. Here's a simple static redirect:

<action name="createSalesOrderConfirmation" class="sales.CreateSalesOrderAction">
    <result name="redirect" type="redirect-action">
        <param name="actionName">displaySalesOrder</param>
        <param name="namespace">/order/sales</param>
    </result>
</action>

This is fairly straight forward. The type of the result is "redirect-action". You set parameters on the result using the param tags. In this case you set the actionName to displaySalesOrder, and the namespace to "/order/sales".

Dynamic Parameters for Redirects

Struts 2 supports passing dynamic parameters to a redirect, such as the id of a newly created entity, so you can display it.

The action-redirect result takes several parameters to help with this, which will not be parsed:

  • actionName
  • namespace
  • method
  • encode
  • parse
  • location
  • prependServletContext

To pass dynamic parameters to a redirect-action result you at a minimum you need to set "parse" to true. As follows:

<action name="createSalesOrderConfirmation" class="sales.CreateSalesOrderAction">
    <result name="redirect" type="redirect-action">
        <param name="actionName">displaySalesOrder</param>
        <param name="namespace">/order/sales</param>
        <param name="parse">true</param>
        <param name="id">${order.id}</param>
    </result>
</action>

In this redirect-action result we've added two parameters using param tags. The parse parameter tells Struts 2 to parse any additional parameters using the OGNL expression language. The "id" parameter tells Struts 2 to add this as a parameter to the next action by evaluating the OGNL statement against the current value stack.

In this case my current action, not the one I'm forward to, has an order property, which has an id property. This statement will add the value of this property to the redirect resulting in a forwarding URL like this:

http://www.mydomain.com/mycontext/order/sales/displaySalesOrder.action?id=123

You can set additional parameters on the redirect, and have them encoded using the "encode" parameter, or set the method using the "method" parameter.

Another case of losing request parameters

The Assertion Consumer (SAML V1.1 Browser/POST Profile)
receives a POST Form (with Response and Assertion) from external.

On the Source Site I create the SAMLResponse in a JSP with

Another case of losing request parameters

...continuation:
s:form method="post" action="the destination URL"...

If the Assertion Consumer is a simple Servlet, the request.getMethod()
shows the POST and all Parameters are there. With Struts2 I receive a GET
and see no Parameters.
How can I convince Struts2 to accept the POST?

Don't use ${id}

Beware, for some reason you cannot use ${id} as its value gets garbled.

I.e. the following doesn't work, even if you have a getId() method on your action:

${id}

Re: Don't use ${id}

I use ${id} all the time in my application. I'm not sure what's happening in your setup, but I'd look into it more.

Mark

Redirection Question

Hi Mark,

I want to redirect a user to his previous visited URL, after a successful login.
For example, a user clicked on:
/mySite/products/purchase.action?id=45&try=234

and this takes him to the login page. I do that by using a login interceptor on purchase.action. I store this URL in the session in the login interceptor. How do I redirect back to this URL? (Of course this URL can vary depending on where the user was).

Thanks.

redirect to a specified JSP page

redirect to a specified JSP page, and in the JSP page redirect to the URL(from session).
But I also has a question: how could you get the "previous visited URL" in interceptor?

try refer

havd try on:
request.getHeader("referer");

Why %{}

It's just annoying that to invoke OGNL parsing, you have to wrap your expression in %{expr} on the JSP, but in ${expr} in the struts.xml. Do you know of a specific reason or is it just one of those annoying inconsistencies?

Re: Why %{}

I would guess it's that way because ${} is taken by the JSP EL.

Redirect loses request parameters

Hi Mark,

I know it's almost a year since you posted this. I still thought you might respond to a query:

I have a Sign-up page which takes in username, password, name and phone number. The signup page is accessed via /mysite/signup.action. When the "Register" button is submitted on Signup.jsp, it submits to /mysite/account/create.action where validation happens. If the form data is invalid, I redirect to signup.action but I cannot retain the valid values entered by the user!
I found a Message Store interceptor but that is geared to work with error messages.

Any thoughts?

Re: Redirect loses request parameters

Well, I would say that your design is fundamentally flawed. A redirect will use an HTTP GET. You shouldn't be changing data in the system using a GET. I would suggest that you do your model work in /mysite/account/create.action. I would "sign them in" in create.action, the redirect to a welcome page.

Mark

Redirect to referrer

You could do something like this.

In the action class

public void prepare() throws Exception {

if ( request != null ) {
String referer = request.getHeader( "Referer" );
logger.debug(this, "prepare()","referer is '%'", referer);
if ( referer != null ) {
setRedirectUrl( referer );
} else {
setRedirectUrl( request.getContextPath() );
}

}

In the struts configuration


<action name="loginCommit" class="loginAction" method="loginCommit">
<result name="input" type="redirect">${redirectUrl}</result>
<result name="success" type="redirect"\>${redirectUrl}</result>
</action>

Don't forget the getter

Great example. I can find answers in this site not in Struts2 books or other sites. At any rate, the above example works great as long as you remember to have a getter in your action for the object you want to access from the stack. I typically don't want to clutter up my actions code with unnecessary getters when only a setter is sufficient. Took me a minute to figure out I had forgotten the getter in order for the example to pick my ID off the stack. Thanks again for the new knowledge!

Problems with the post

I know that this is not the best place to post this but i'm doing it anyway because it seems that you have experience tiwth struts 2.
After i read this article i tried in my code, and everithing works except from the fact that my resulting jsp is empty.
Let me explain you everyting. I have a page that has a button to star the register of a new visit for a pacient, an action called "pacienteAction" do the job and the result is a redictAction to "datosDemograficosAction", this action loads the data of the pacinte from the database and i want to display this data in a jsp. All sentences related with the databse are ok and work fine. In "datosDemograficosAction" i'm exposing the model with ModelDriven interface and the model is the value object that i fill with info from the database.
The problem is that even i have my value object with data, when the jsp is displayed, all the fields are empty.

I know i can work around this problem and use the session but that is not the best/practical/optimal way to do this.

If you can give me some advice i really appreciate

By the way, sorry by my bad english

WOW

COOL

Caught OgnlException

It works but I cannot get rid of this nasty exception
in the console ...
This is registred as a bug in struts bug tracking

WARNING: Caught OgnlException while setting property 'town' on type
...

Solved?

Hi, I have the same error. Any proposals?

Caught OgnlException

It works but I cannot get rid of this nasty exception
in the console ...
This is registred as a bug in struts bug tracking

WARNING: Caught OgnlException while setting property 'town' on type 'org.apache.struts2.dispatcher.ServletActionRedirectResult'.
ognl.NoSuchPropertyException: org.apache.struts2.dispatcher.ServletActionRedirectResult.town
at ognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:132)
at com.opensymphony.xwork2.util.OgnlValueStack$ObjectAccessor.setProperty(OgnlValueStack.java:68)
at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:1670)
at ognl.ASTProperty.setValueBody(ASTProperty.java:101)

I agree this exception is

I agree this exception is really annoying and should be fixed

Looks like this is fixed in 2.1.7

There was a bug posted for this:

https://issues.apache.org/struts/browse/WW-1714

Looks like it has been fixed in 2.1.7

Brendan

excited to hear that!

i came across this problem too...but found no solution anywhere...
thanks..

Aran