Versions Compared

Key

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

...

In

...

the Using Tags lesson,

...

we

...

implemented a Logon form. In the Coding Actions lesson, we interpret the Logon form, and return a different result code depending on the circumstances.

If you have coded along, you can open the Logon action

Code Block
http://localhost:8080/tutorial/Logon.action

and enter a likely username and password. Since we haven't given the Action any behavior, the mapping redisplays the default Logon.jsp page.

Let's add an Action class that will make the Logon form more interesting.

The Code

Just as an example, we can examine the username and password values. If either or both properties are empty, return INPUT, so that we can collect a valid Logon. Otherwise, return SUCCESS.

Code Block
formatxml
titleLogon.java
borderStylesolid

package tutorial; a use case that displayed a message with a dynamic timestamp. In this lesson, we create a workflow that displays input from a data-entry form.

The form will ask for your name. If you enter "Bob" and click the submit button, the page will display "Hello, Bob\!". If you don't enter a name, the page will display: "Hmmm, you did not enter a name. Please try again\!"

In the [Hello World] lesson, there were three components: the Action class, the result page, and the action mapping. In this lesson, we will add a fourth component: an input form.

h2. HTML Form With Data, Using Getters and Setters


h3. Create the HTML form

The framework includes a library of special tags that you can use to write more powerful forms, but "plain old HTML forms" work just fine too.
{code:html|title=helloName.html}
<html>
<head>
	<title>A simple form with data</title>
</head>
<body>
	<p>What is your name?</p>

	<form action="helloName.action" method="post">
		<p><input type="text" name="name"></p>
		<p><input type="submit" value="Submit your name." /></p>
	</form>

</body>
</html>
{code}

h3. Create the Action class

The HTML form submits an attribute called "name", and the Action class provides a corresponding JavaBean property.
{code:java|title=
package tutorial;

import com.opensymphony.xworkxwork2.ActionSupport;

public class HelloLogon extends ActionSupport {

  String name;

  public voidString setNameexecute(String value)) throws Exception {
    name = value;
  }

  public String getName() {
    return name;
  }

  public String execute() throws Exception {
    if (name == null || name.length() == 0)
      return ERRORif (isInvalid(getUsername())) return INPUT;
        if (isInvalid(getPassword())) return INPUT;
    else
      return SUCCESS;
  }

}
{null}

h3. Create the action mapping}

We can just add aprivate newboolean action mapping to the file we started in the [Hello World] lesson.
{code:xml|title=action.xml}
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd">

<xwork>
  <include file="action-default.xml" />

  <package name="default" extends="action-default">

    <action name="helloWorld" class="tutorial.HelloWorld">
      <result name="success">helloWorld.jsp</result>
    </action>

    <action name="helloName" class="tutorial.HelloName">
      <result name="success">helloName-success.jsp</result>
      <result name="error">helloName-error.jsp</result>
    </action>

  </package>
</xwork>
{code}

h3. Create the success and error pages

The Action can select between two outcomes, "success" and "failure".
{code:html|title=helloName-success.jsp}
<%@ taglib uri="action2" prefix="saf" %>
<html>
<head>
    <title>Success Page</title>
</head>
<body>
    <p>
      Hello, <saf:property value="name" />!
    </p>
</body>
</html>
{code}
{code:html|title=helloName-error.html}
<html>
<head>
	<title>Error Page</title>
</head>
<body>
<p>
Hmmm, you did not enter a name. Please try again!
</p>
</body>
</html>
{code}

h3. Try it\!

If you are coding along, go ahead and try your form now. Open the input page ([http://localhost/tutorial/helloName.html]), and click the submit button to see what happens. Try it with and without entering a name.
{warning:title=Don't forget!}
Compile your Action to {{WEB-INF/classes}} and restart your container if necessary.
{warning}

h3. How the code works

There are two differences between this example and the [Hello World] lesson.
# When the Action is called, {{setName}} is passed the contents of the {{name}} form field.
# When the Action's {{execute}} method returns, the framework has two options. If the string "error" returns, the framework will select {{helloName-error.jsp}} as the result. If the string "success"  returns, then {{helloName-success.jsp}} is selected.

Let's try a slightly different approach to solve the same user case.

h2. HTML Form With Data, Without Using Getters and Setters

In our first form, we needed to capture the field {{name}} and to do that we added the getters and setters {{getName}} and {{setName}} to the Action class, as well as the private variable {{name}}. A larger application with dozens of forms and hundreds of form fields could need several hundred getters and setters. Let's try that same use case again, but without the JavaBean methods.

h3. Create the HTML form

Let's use the same HTML form, but change the form Action to {{helloName2.action}}:
{code:html|title=helloName.html}
<html>
<head>
  <title>A simple form with data</title>
</head>
<body>
   <p>What is your name?</p>

   <form action="helloName2.action" method="post">
     <p><input type="text" name="name"></p>
     <p><input type="submit" value="Submit your name." /></p>
   </form>
</body>
</html>
{code}

h3. Create the Action class

{code:java|title=HelloName2.java}
package tutorial;

import com.opensymphony.xwork.ActionSupport;
import org.apache.struts.action2.interceptor.ParameterAware;

import java.util.Map;

public class HelloName2 extends ActionSupport implements ParameterAware {

  Map parameters;

  public Map getParametersisInvalid(String value) {
        return (value == null || value.length() == 0);
    }

    private String username;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }

    private String password;
    public String getPassword() {
    return parameters;
  }

  public void setParameters(Map parameters) {return password;
    this.parameters = parameters;}
  }

  public Stringvoid execute() {
    String[] name = (String[]) parameters.get("name");setPassword(String password) {
    if(name == null || name[0] == null || name[0].length() == 0)
      return ERROR;
    else
      return SUCCESS;
  }
}
{code}

h3. Create the action mapping

{code:xml|title=action.xml}
<!DOCTYPE xwork PUBLIC "-//OpenSymphony Group//XWork 1.0//EN" "http://www.opensymphony.com/xwork/xwork-1.0.dtd">

<xwork>
  <include file="action-default.xml" />

  <package name="default" extends="action-default">

     <action name="helloWorld" class="tutorial.HelloWorld">
       <result name="success">helloWorld.jsp</result>
     </action>

     <action name="helloName" class="tutorial.HelloName">
       <result name="success">helloName-success.jsp</result>
       <result name="error">helloName-error.jsp</result>
     </action>

     <action name="helloName2" class="tutorial.HelloName2">
       <result name="success">helloName2-success.jsp</result>
       <result name="error">helloName-error.jsp</result>
     </action>

  </package>
</xwork>
{code}

h3. Create the success and error pages

We can use the same error page, but we'll need a slightly different success page {{helloName2-success.jsp}}. The only difference is the {{<saf:property>}} tag.
{code:html}
<%@ taglib uri="action2" prefix="saf" %>
<html>
<head>
  <title>Success Page - Without Using Getters and Setters</title>
</head>
<body>
  <p>
    Hello, <saf:property value="parameters.yourName" />!
  </p>
</body>
</html>
{code}

h3. Try it\!

Go ahead and try it now. Load {{helloName.html}}, enter "Bob" in the text field, and click the form submit button. You should see {{helloName2-success.jsp}} saying "Hello, Bob\!"
{warning:title=Don't forget!}
Compile your Action to {{WEB-INF/classes}} and restart your container if necessary.
{warning}

h2. How the code works

Instead of a setter {{setName}} accessing a private variable {{name}} in the Action class, {{setParameters}} magically extracts everything from the {{request}} object and puts the attributes into a private local Map, {{parameters}}. In the {{execute}} method, we can get the value from the {{parameters}} Map instead of looking for a {{name}} property. So far so good.

Back on the {{helloName2-success.jsp}} page, {{<saf:property value="name" />}} isn't going to work any more, because there is no {{getName()}} method in the Action. Instead, {{<saf:property value="parameters.name" />}} calls the {{getParameters}} method, and is able to get the value of the "name" field. Pretty neat\!

h2. Summary

Before processing an Action, the framework matches any Action properties with request attributes. If a match is found, the attribute value is set to the Action property. The Action can process the value, and the SAF tags can present the value too. Rather than define a separate property for each attribute, you can define a single Map property instead. In that case, all the request attributes will be set to the Map automatically.
|| Next | Onward to [Understanding Results] ||
|| Prev | Return to [Hello World] || this.password = password;
    }

}

How The Code Works

The framework automatically populates the username and password properties for us. All that's left to do is checking to see if either property is empty.

What to Remember

The Actions do the "heavy lifting" in a web application. Actions interact with data base systems and business rule engines, so that we can turn "billboard" HTML into a rich, dynamic web experience.

After doing its work, an Action returns a result code to indicate what the framework should do next. Often, the next step is to go onto the "success" result. Other times, we might need to go to an "error" result instead. In either case, the Action does not worry about generating the response, only deciding which logical result to present next.

(lightbulb) For more about Actions, see Big Picture in the Core Developers Guide.

Next

Onward to Selecting Results

Prev

Return to Using Tags