views:

6201

answers:

10

Hi there.
I'm using Struts 2. I'd like to return from an Action to the page which invoked it. Say I'm in page x.jsp, I invoke Visual action to change CSS preferences in the session; I want to return to x.jsp rather than to a fixed page (i.e. home.jsp)
Here's the relevant struts.xml fragment:

<action
   name="Visual"
   class="it.___.web.actions.VisualizationAction">
   <result name="home">/pages/home.jsp</result>
</action>

Of course my VisualizationAction.execute() returns "home". Is there any "magic" constant (like, say, INPUT_PAGE) that I may return to do the trick?
Must I use a more involved method (i.e. extracting the request page and forwarding to it)?
T.I.A.

+1  A: 
return INPUT;

will do the trick. INPUT constant is defined in Action interface itself. It indicates that action needs more input.

By calling page if you meant the page that took you to the action input page, then your input page will have to store HTTP header "Referer" in the request scope for the Action.

nikhilbelsare
A: 

Thanks for your kind (and prompt) reply, nikhilbelsare.
I tried return INPUT; but I got a No result defined for action it._.web.actions.VisualizationAction and result input**
error message (pretty much expected because I did not define "input" anywhere in my struts.xml).
What I really wanted to do was Struts 2 to automagically identify the referring page and forwarding me to it, since the action is invoked from many different pages, and I have no means of predicting the INPUT.
I guess I'm stuck with parsing the header...

Manrico Corazzi
+1  A: 

Alternatively, you can include a hidden field in each of your pages that tells Action which page to redirect to. This way you can get finer control over things.

nikhilbelsare
+1  A: 

My first thought was to use the HTTP referer information, but this is fraught with all sorts of unreliability problems.

See this article on WikiPedia as a starting point

+1  A: 

My next thought was to add a filter that kept trackof the last couple of "actions" that were invoked. You could then write a view resolver that simply retrieved the last-but-one entry from this list and then redirected to it.

This scheme would also fail, if you have AJAX operations on a page, which are themselves actions. This would cause the url of the main page to be lost, because it would no longer be the 'last-but-one' action.

+1  A: 

At the moment, I tend to agree with nikhilbelsare - you need to pass the URL, that you want to return to, into the Visualisation Action.

Whether this is done via a form field or a request parameter is largely a matter of taste.

If the link to the visualisation action is likely to appear on most - if not all - pages, then you could place the markup in your site template (Sitemesh/Tiles etc) and have it automatically append the current URL onto the URL of the visualisation action, as an encode parameter.

I'm in the process of setting up a Struts2 site myself, so will investigate further and report back if I come up with a neat(er) solution.

+1  A: 

You can use a dynamic result in struts.xml. For instance:

<action
   name="Visual"
   class="it.___.web.actions.VisualizationAction">
   <result name="next">${next}</result>
</action>

Then in you action, you create a field called next. So to invoke the action you will pass the name of the page that you want to forward to next. The action then returns "next" and struts will know which page to go to.

There is a nicer explanation on this post: Stack Overflow

Vincent Ramdhanie
A: 

I prefer the way when you navigating users by particular actions.

http://domain.com/myAction.action

You could use some parameter as indicator, that you want to change current design: i.e.

http://domain.com/myAction.action?changeDesign=silver_theme

So then, you write some struts 2 interceptor, which logic is to check the presence of such parameter 'changeDesign', and this interceptor will do nessesary work of changing design and will control workflow. With interceptor you decouple your actions from crosscutting logic.

Pavel Rodionov
+1  A: 

My solution would involve one interface and one interceptor. You implement the following interface for all actions to which you are likely to want to redirect:

public interface TargetAware {
  public String getTarget();
  public void setTarget(String target);
}

The interceptor simply ensures that the target is set, if required:

public class SetTargetInterceptor extends MethodFilterInterceptor implements Interceptor {
   public String doIntercept(ActionInvocation invocation) {
      Object action = invocation.getAction();
      HttpServletRequest request = (HttpServletRequest) invocation.getInvocationContext().get(StrutsStatics.HTTP_REQUEST);
      if (action instanceof TargetAware) {
         TargetAware targetAwareAction = (TargetAware) action;
         if (targetAwareAction.getTarget() == null)
            targetAwareAction.setTarget(getCurrentUri(request));
      }  
      return invocation.invoke();
   }

   // I'm sure we can find a better implementation of this...
   private static String getCurrentUri(HttpServletRequest request) {
      String uri = request.getRequestURI();
      String queryString = request.getQueryString();
      if (queryString != null && !queryString.equals(""))
         uri += "?" + queryString;
      return uri;
   }

   public void init() { /* do nothing */ }
   public void destroy() { /* do nothing */ }
}

From then on, once these two bits are in place and your actions implement the TargetAware interface (if you expect to have to redirect to them), then you have access to a target parameter in your JSPs whenever you need it. Pass that parameter on to your VisualizationAction (which might as well implement also the TargetAware interface!), and on SUCCESS, redirect as explained by Vincent Ramdhanie:

<action name="Visual" class="it.___.web.actions.VisualizationAction">
   <result type="redirect">
      <param name="location">${target}</param>
      <param name="parse">true</param>
   </result>
</action>

I did not try every single detail of this strategy. In particular, beware of the notation surrounding the redirect result type (depending on your specific version of Struts2: 2.0.x and 2.1.x may differ on this...).

pierdeux
+1  A: 

ok, in your class it.___.web.actions.VisualizationAction, you must return a string value containing INPUT, then, on struts.xml you have to set something like this:

<action name="Visual" class="it.___.web.actions.VisualizationAction">
   <result name="input">yourJspPage.jsp</result>
</action>

this will lead you to the page you want. This should work, I've been working on struts2 along 2 months

Giancarlo