How to use multiple forms / actions in a single view in Struts 2

nharrer picture nharrer · Jul 18, 2015 · Viewed 7.8k times · Source

I have a search box which is displayed on every page. The JSP code for the search box is inserted into every page via tiles.

The search box has a form and an action class SearchAction which needs to preload some properties for drop down boxes. The SearchAction class has an input() method, which does this initialization.

Some pages also have their own form in the main area. Also with their own action class. They also have an input() method which does some preloading.

  1. Is it possible to use two actions in the same view?
  2. How can each form have access to it's own actions's properties.
  3. And how could I manage to have the input method of both action classes be called before the JSP is rendered?

Update:

I am adding a trimmed down example, since it's probably not clear what I am trying to do. It's a register page register.jsp with an RegisterAction. And the page also contains the search form. (BTW: I left out the getter/setter and other stuff in the action classes to keep it short):

register.jsp:

<s:form action="executeSearch">
    <s:textfield key="name" label="Name"/>
    <s:textfield key="age"  label="Age"/>
    <s:submit/>
</s:form>

<s:form action="executeRegister">
    <s:textfield key="firstName" label="First Name"/>
    <s:textfield key="lastName" label="Last Name"/>
    <s:textfield key="age" label="Age"/>
    <s:submit/>
</s:form>

struts.xml:

<action name="*Search" class="action.SearchAction" method="{1}">
    <result name="success">/searchresult.jsp</result>
</action>

<action name="*Register" class="action.RegisterAction" method="{1}">
    <result name="input">/register.jsp</result>
    <result name="success">/registerOk.jsp</result>
</action>

SearchAction.java:

public class SearchAction extends ActionSupport {

    private String name;
    private int age;

    @Override
    public String input() throws Exception {
        // preload the search form with some demo data
        name = "test";
        age = 20;
        return INPUT;
    }

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }

    ...
}

RegisterAction.java:

public class RegisterAction extends ActionSupport {

    private String firstName;
    private String lastName;
    private int age;

    @Override
    public String input() throws Exception {
        // preload the register form with some demo data
        firstName = "John";
        lastName = "Rambo";
        age = 10;
        return INPUT;
    }

    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }

    ...
}

Let's say I call the action inputRegister.action. Then RegisterAction.input() is called. The properties are set. And result SUCCESS causes register.jsp to be rendered.

But what about my search form. How do I get access to the search action and it's model. Neither of those are on the ValueStack of course. And neither do I see a way to call any methods of SearchAction in order to initialize it's model. I deliberately choose age to be in both action classes. In the rendered page you can see that the search form also accesses the RegisterAction-properties (because that's on top of the ValueStack). But it needs to access SearchAction. It must display 20 and not 10.

Rendered Jsp Page

I am clearly doing it wrong. But even after a lot of googling, I still did't find out the right way to do it.

Answer

Roman C picture Roman C · Jul 18, 2015

The concept of the view is used to perform any number of actions, and any action can have any number of results. A result is used to return a view. The action that returns a view is placed on top of the ValueStack to be easy accessible via evaluating OGNL expressions. The result view could be mapped to any action in any action class. It knows nothing about action which calls it, but it can determine it, again using OGNL. You can map actions to different method of the same action class, so you don't need to have many input() methods.

EDIT:

You problem is you bounded form fields wrong. Each form should have a separate storage to display it correctly. Fields are bounded by name, and you'd better have a form bean for the search condition variables and put it somewhere in the action context.

<s:form action="executeSearch">
    <s:textfield key="searchBean.name" label="Name"/>
    <s:textfield key="searchbean.age"  label="Age"/>
    <s:submit/>
</s:form>

<s:form action="executeRegister">
    <s:textfield key="firstName" label="First Name"/>
    <s:textfield key="lastName" label="Last Name"/>
    <s:textfield key="age" label="Age"/>
    <s:submit/>
</s:form> 

Note: the key attribute generates name, label, and value.

Each action needs to initialize a searchBean, unless it has a session scope. If you put a bean to a session, then you should use #session. prefix. More about OGNL you can find on the docs page.