Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

This page is meant to be a list of issues and solutions that users ave encountered while migrations migrating existing SAF1 Struts 1 application to SAF2Struts 2, or developing new Webwork-based applications. If you have a solution to the issue that will of course be most helpful, but even if you don't it is worth noting what you encountered none the less in the hopes that someone else can come along and answer it for you, and the rest of us.

  • How do we change the location of the struts.xml file?
  • How do we set checkboxes to false (on uncheck)

...

  • http://forums.opensymphony.com/thread.jspa?threadID=23601&tstart=0
  • How

...

  • can we set the focus on a form field

...

  • http://forums.opensymphony.com/thread.jspa?threadID=23777&tstart=0
  • What is the analogy to ForwardAction?

One of the Struts "best practices" is that all requests within an application should go through Struts. So, you should generally never reference a JSP directly for instance. To help with this, Struts provides the !ForwardAction, which is more or less an Action that does nothing, it just immediately returns and forwards to the URI as configured. Webwork does not appear to have a direct analogy to this. However, it is easy to get the same effect in a couple of possible ways.

First, you can write a simple Action like so:

Code Block

package com.company.app;

import com.opensymphony.xwork.Action;

public class ForwardAction implements Action {

  public String execute() {
    return SUCCESS;
  }

}
  • How do we extend an action mapping in struts.xml?
  • Can we use DynaBeans?
  • How do we set a token to track duplicate submits?

How do we change the location of the struts.xml file?

Struts 2 uses a different approach to loading the configuration. The initial struts.xml is loaded from the root of the classpath. The easiest way to set that up is to put the struts.xml under the classes folder.

If maintaining the struts.xml under classes doesn't work for you, then use the "bootstrap" struts.xml to include whatever other struts.xml's you'd like.

Code Block

<struts>
   <include file="..\struts.xml"/>
</struts>

Or, chuck it all and use Zero Configuration (smile)

How do we set checkboxes false (on uncheck)?

In Struts 2, checkboxes are stateful, and we don't need to do that anymore.

Just treat the checkbox like any other tag. The framework will notice if a checkbox is "missing" from a request and inject a false value for that checkbox.

How can we set the focus on a form field?

Struts 1 generates a little JavaScript that helps set the focus, if you specify the field in the JSP.

Another solution is to use a generic Javascript that automatically seeks the first enabled form field on page.

(Building this script into Struts 2 is being considered.)

What is the analogy to ForwardAction?

The default Action class (ActionSupport) returns SUCCESS by default, and SUCCESS is the default result. Using an action to forward directly to a page is easyThen, configure an Action like this:

Code Block
<action name="justAForwardWelcome" class="com.company.app.ForwardActionFoo">
  <result name="success">pageToDisplay<result>/pages/Welcome.jsp</result>
</action>

Now you can use that !ForwardAction whenever you like, just as you would in Struts. Alternatively, if you don't want to have a whole Action just for that, you can simply have a method in an existing Action (named something other than execute, let's say "gotoJSP" for the sake of argument) and configure an Action like so:

Code Block

<action name="justAForward" class="com.company.app.SomeExistingAction" method="gotoJSP">
  <result name="success">pageToDisplay.jsp</result>
</action>

An even easier solution however, as suggested by Ted Husted in the thread referenced below, is to use the !ActionSupport class. Your mapping then is just:

Code Block

<action name="justAForward" class="com.opensymphony.xwork.ActionSupport">
  <result name="success">pageToDisplay.jsp</result>
</action>

Because the default implementation of execute() in !ActionSupport simply returns SUCCESS, and since execute() is called by default when no method is specified in the mapping, this does exactly the same thing as the Action code shown above, without the need for a custom class being introduced.

Here is a reference to the thread discussing this: http://forums.opensymphony.com/thread.jspa?threadID=23755&tstart=15

How do you emulate the default="true" attribute of a SAF1 Action mapping?

In SAF1, it is possible to set the default attribute of an Action mapping in struts-config.xml to true.  Then, any request coming in to ActionServlet that does not match a configured Action mapping will result in that mapping being executed.

SAF2 does not (at this point in time at least) provide this attribute.  However, there is a way to get the same effect.

Within xwork.xml (struts.xml?), on a per-package basis, you can have the following: 

Code Block

<default-action-ref name="defaultAction">

 This says that for the package this is declared in, the mapping with the name defaultAction will be executed when any request comes in that does not match any other mapping.


How do we emulate the default="true" attribute of a Struts 1.x Action mapping?

Rather than tag the action as being the default, the default action is set by name using default-action-ref element.

Code Block

<default-action-ref name="defaultAction">

By using an element, rather than an attribute, packages can inherit the default action name.

How do we extend an action mapping in struts.xml?

Starting in Struts 1.3, we can use the "extends" attribute in our Struts configuration Action mapping to have it inherit properties from a base mapping. In Struts 2, that technique is no longer necessary because we have packages. We can create a package, then set for that package the default Result type, Interceptor chain, and global results. This leaves very little information to actually be included in an action element.

Here is an example of declaring a custom package:

Code Block

<package name="chat" extends="struts-default" namespace="/chat">
  <global-results>
    <result name="login" type="freemarker">/chat/chatLogin.ftl</result>
  </global-results>
  <default-interceptor-ref name="basicStack"/>
  ...
</package>

In fact, packages themselves can extend other packages, as the "chat" package extends "struts-default" in the above example.

Can we use DynaBeans?

Sure, but first, ask "Do we want to use DynaBeans at all?"

Typically, DynaBeans are used to emulate a plain old JavaBean that is utilized by the business logic. If that is the case, then we can just use the plain old JavaBean directly. Struts 2 will happily cope with rich properties, like date fields. We don't have to reduce everything to a String anymore.

Otherwise, DynaBeans can be treated as a regular Java object, if the particular implementation contains a getMap() method. This method lets OGNL, the Struts 2 expression language, know how to access and set data. DynaBean variants like the LazyDynaBean can create themselves on-the-fly, where other more static types might need to be created in your Action's constructor before being used.

How do we set a token to track duplicate submits?

In Struts 2, there shouldn't be any token code in an Action class at all. The Interceptors are designed to do all the work. There are three flavors, the Token Interceptor, the Token Session Interceptor, and the Execute and Wait Interceptor.

Token Interceptor

The Token Interceptor is most like the Struts 1 approach, except that we don't have to change the Action class to add a lot of busy code. The trade off is that we do have to include the token tag in the form, to bootstrap the process. In Struts 1, we set the token in the Action, and the form tag detected it. In Struts 2, we set the token in the page, and the Interceptor detects it.

If the Interceptor does detect a duplicate submit, then it automatically returns an "invalid.token" result code, which can be handled via the action mapping.

Token Session

The Token Session Interceptor tries to be even more automatic by attempting to display the same response that the original, valid action invocation would have displayed if no multiple requests were submitted in the first place.

Execute and Wait

The Execute and Wait Interceptor embraces long-running taks by presenting a progress meter as the Action runs in the background.

Next: What is the ActionContext?

...

...

This material originally adopted from: http://wiki.apache.org/struts/IssuesAndSolutions.