To run this sample project Eclipse, download and install the WAR file:
StrutsMiscell.war.
In NetBeans, download the
StrutsMiscell.zip archive.
These JAR files are needed for NetBeans:
Afterwards, the BEAN is available for usage as a list.
For some reason that does not seem obvious, a single definition
cannot use both put-attribute and put-list-attribute tags;
multiples of either one or the other, only. In order to
circumvent this problem, each tiles definition that requires
both lists and regular attributes is represented by two
levels of extension. There are two occurrences of this
construction in our tiles definition file:
You'll notice three attributes in the
put-attribute, put-list-attribute and add-attribute
tags:
name, type, value
The name, of course, is what identifies it for the JSP
file usage. The value attribute is used to provide
the content for a single put-attribute or for the
add-attribute as part of a list. How the content is
obtained by the value depends on the type, which goes
like this:
type="string": the value is meant to be taken literally
type="template": the value is meant to be the execution of
a JSP script
There is apparently a default assumption about the what
the type is if it is not explicitly mentioned: if the
value starts with a "/",
the type is assumed to be "template";
otherwise it is assumed to be "string".
This allows us to use this generic script
to generate simple informational output:
info.jsp
${param.info}
nav.jsp variation
The generation of navigational links has been written
somewhat differently.
util.Nav
package util;
import java.util.*;
public class Nav {
private Map<String, String>
links = new LinkedHashMap<String, String>();
public Nav() {
links.put("welcome", "Home");
links.put("sess_input", "Session Example");
links.put("login_input", "Login Example");
links.put("ajax_input", "Ajax Example");
}
public Map<String, String> getLinks() { return links; }
}
nav.jsp
<%@taglib uri="/struts-tags" prefix="s"%>
<s:bean name="util.Nav" var="nav" />
<table class="nav">
<tr>
<s:iterator var="entry" value="#nav.links">
<td><a href="<s:url action="%{#entry.key}" />">${entry.value}</a></td>
</s:iterator>
</tr>
</table>
Instead of pushing the nav bean on the value stack and
accessing its links property we use the notation "#" to
access the bean directly:
<s:iterator var="entry" value="#nav.links">
The struts config file
The main new concept introduced here is the wildcard
action name which allows a given action definition
tag to handle multiple actions. For example:
The Sess Bean and its invoking script illustrate how to
access and maintain session information in the action handlers.
The key ingredient is the class:
import com.opensymphony.xwork2.ActionContext;
which gives access to the session through the call:
ActionContext.getContext().getSession()
Using this we can control the session contents using the
methods:
get("attr") // retrieve session object for this attribute
put("attr",obj) // store session object for attribute
This example compares info and sessInfo properties as
set by the sess.jsp script. The former is a usual
request-stable property and the latter, a session-stable
property. The relevant portion of struts.xml is:
package action;
import com.opensymphony.xwork2.ActionSupport;
public class Login extends ActionSupport
{
private String username;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
@Override
public String input() { return "initial"; }
@Override
public String execute() { return "success"; }
}
The new feature is the automatic validation effected by
this XML file:
action/Login-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="username">
<field-validator type="requiredstring">
<message>Username is required</message>
</field-validator>
</field>
</validators>
Both the name and the positioning of this file are important.
The name is of the format:
ACTION_BEAN-validation.xml
I believe the "-validation.xml" part is case insensitive.
This is placed the same directory as the ACTION_BEAN itself.
This validation example ensures that the username field,
when trimmed of whitespace, is non-empty; i.e., there must
be at least one non-whitespace character.
It's essential to understand the behavior of this validation.
Note our first usage of the ActionSupport class:
public class Login extends ActionSupport
We could have done this in all previous classes, but we
wanted to illustrate that, for the most part, Action objects
are simple pojos (plain old java objects). In this
case it is necessary. Here is how it works:
The special input method is recognized by struts as
the one method which does not do validation. This is needed
because our first activation of an action, leading to
an input form cannot have the correct form values.
Upon submission, if the validation is successful,
the desired result string (in this case "success" from
the execute method) is returned.
If the validation fails the execute output is ignored
and the "input" string is returned
(this seems like a poor default choice). Our struts action
recognizes the input result as failure.
The choice of non-validating method (input)
is configurable, and
I currently do not know if the failure output string
("input") is configurable or not.
There is an extensive list of
XML validators which can be used, allowing you to
effectively not worry about doing validation whatsoever within
the action class.
Reentrant version with automatic error generation
Struts has the ability to "put the errors into the form," in particular,
using the error messages associated with the validation file. This is
a very simple modification:
Modify the layout.jsp file adding these two lines
(indicated by bolding):
Restart the server (if necessary) and run the script.
You will see several changes:
The label is italicized. This (and others) is the effect of adding
the tag:
<s:head />
to the layout. Behind the scenes what is added are two files extracted
from the "struts" support folder provided by the struts jar file:
The style file: struts/xhtml/styles.css
The javascript file: struts/utils.js
When you generate the error you'll see that
The error message from the validation script is entered in red above the
User Name field.
The label is red.
and enter without input. You'll see two changes: an
entry above the
Sample Ajax usage
This is our first venture into using AJAX with Struts.
Apparently Eclipse's internal browser does not work
with some aspect of the JavaScript, so don't use it to
test this.
The same Login action class is used as in the previous
example. The relevant script is:
ajaxlogin.jsp
<%@taglib uri="/struts-tags" prefix="s" %>
<s:form action="ajax_execute">
<s:textfield name="username" label="User Name" />
<s:submit />
</s:form>
which is essentially the same as before, but the action
call differs. The initial action from the navigational link
is "ajax_input" and the struts setup is this:
The two results "success" (when valid)
and "input" (whe not valid)
do not generate tiles results.
Instead we want these to
be simple data outputs gnerated by the info.jsp script
which can be used by JavaScript.
info.jsp
${param.info}
We use the jQuery setup with form plugin
introduced through the tiles definitions:
Finally, the key JavaScript file controls the activations:
login.js
$(function() {
$('#ajax_execute').ajaxForm(
function(data) {
data = data.trim()
alert(data)
if (data != "success")
$('#ajax_execute_username').css("background-color", "red")
}
)
$('#ajax_execute_username').focus(function(){
$('#ajax_execute_username').css("background-color", "white")
})
})
The id values of
ajax_execute_username
are already created by the struts form construction.