In the Hello World Using Tags lesson, we implemented a use case that displayed a message with a dynamic timestamplogin form. 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 "Zaphod" and click the submit button, the page will display "Hello, Zaphod!". If you don't enter a name, the page will display: "Hmmm, you did not enter a name. Please try again!"
HTML Form With Data, Using Getters and Setters
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.
Create a HTML input form
The framework includes a library of special tags that you can use to write dynamic forms, but "plain old HTML" forms work just fine too.
...
<html>
<head>
<title>A simple HTML 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>
interpret the Logon form, and return a different result code depending on the circumstances.
If you have coded along on localhost, you can open the Logon action.
Code Block |
---|
http://localhost:8080/tutorial/Logon.action |
Enter a likely username and passowrd, and press Enter. Since we haven't given the Action any behavior, it redisplaysthe default Logon.jsp
page.
Let's add an Action class that make the Logon page more interesting.
The Code
Just as an example, lets look at the username and password values. If either or both are empty, return INPUT, so that we can collect a valid logon. Otherwise, return SUCCESS.
Code Block |
---|
Create the Action class
The HTML form submits an attribute called "name", and the Action class provides a corresponding JavaBean property.
Code Block | java | java | title | HelloName.java
---|
package tutorial; import com.opensymphony.xwork2.ActionSupport; public class HelloNameLogon extends ActionSupport { public String execute() throws Exception { if (getName() == null || getName().length() == 0) isInvalid(getUsername())) return ERRORINPUT; else if (isInvalid(getPassword())) return SUCCESSINPUT; } private String name; public String getName() { return nameSUCCESS; } publicprivate voidboolean setNameisInvalid(String namevalue) { this.name = name; } } |
Create the action mapping
We can just add a new action mapping to the file we started in the Hello World lesson.
...
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="struts-default.xml" />
<package name="actions" extends="struts-default">
<action name="HelloName" class="tutorial.HelloName">
<result name="success">HelloName-success.jsp</result>
<result name="error">HelloName-error.html</result>
</action>
</package>
</struts>
Create the success and error pages
The Action can select between two outcomes, "success" and "failure".
...
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Success Page</title>
</head>
<body>
<p>
Hello, <s:property value="name" />!
</p>
</body>
</html>
...
<html>
<head>
<title>Error Page</title>
</head>
<body>
<p>
Hmmm, you did not enter a name. Please try again!
</p>
</body>
</html>
Try it!
If you are coding along, go ahead and try your form now. Open the input page (http://localhost:8080/tutorial/HelloName.html), and click the submit button to see what happens. Try it with and without entering a name.
Warning | ||
---|---|---|
| ||
Compile your Action to |
How the code works
There are two differences between this example and the previous Hello World lesson.
- When the Action is called,
setName
is passed the contents of thename
form field. - When the Action's
execute
method returns, the framework has two options. If the string "error" returns, the framework will selectHelloName-error.html
as the result. If the string "success" returns, thenHelloName-success.jsp
is selected.
Let's try a slightly different approach to solve the same use case.
HTML Form With Data, Without Using Getters and Setters
In our first form, we needed to capture the field name
. 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.
Create the HTML form
Let's use the same HTML form, but change the form Action to HelloName2.action
:
...
<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>
Create the Action class
Code Block | |
---|---|
java | java |
title | HelloName2.java | package tutorial; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.interceptor.ParameterAware; import java.util.Map; public class HelloName2 extends ActionSupport implements ParameterAware { public static String NAME = "name"; return (value == null || value.length() == 0); } private String username; public String executegetUsername() { String[] name = (String[]) parameters.get(NAME)return username; } ifpublic (name == null || name[0] == null || name[0].length() == 0) return ERROR;void setUsername(String username) { else this.username return SUCCESS= username; } Mapprivate String parameterspassword; public MapString getParametersgetPassword() { return parameterspassword; } public void setParameterssetPassword(MapString parameterspassword) { this.parameterspassword = parameterspassword; } } |
Create the action mapping
...
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="struts-default.xml"/>
<package name="actions" extends="struts-default">
<action name="HelloName" class="tutorial.HelloName">
<result name="success">/HelloName-success.jsp</result>
<result name="error">HelloName-error.html</result>
</action>
<action name="HelloName2" class="tutorial.HelloName2">
<result name="success">HelloName2-success.jsp</result>
<result name="error">HelloName-error.html</result>
</action>
</package>
</struts>
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 <s:property>
tag.
...
<%@ taglib prefix="s" uri="/tags" %>
<html>
<head>
<title>Success Page - Without Using Getters and Setters</title>
</head>
<body>
<p>
Hello, <s:property value="parameters.name"/>!
</p>
</body>
</html>
Try it!
Go ahead and try it now. Load (http://localhost:8080/tutorial/HelloName2.html), enter "Zaphod" in the text field, and click the form submit
button. You should see HelloName2-success.jsp
saying "Hello, Zaphod!"
Warning | ||
---|---|---|
| ||
Compile your Action to |
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, <s:property value="name" />
isn't going to work any more, because there is no getName()
method in the Action. Instead, <s:property value="parameters.name" />
calls the getParameters
method, and is able to get the value of the "name" field. Pretty neat!
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 Struts 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 automaticallyWhile the action decides which result to next invoke, it does not decide what the result actually does. For that, we need to turn to selecting results.
Next | Onward to Selecting Results |
---|---|
Prev | Return to Hello World |