Open Source Subnet An independent Open Source community View more

UI tags make Struts look good

The Struts web application framework makes it easy to build Java web apps using a Model-View-Controller architecture. Last time we introduced Struts tags, which let you control page output, interact with data, present information to users, and get information back from them. In that article we focused on generic tags; this time we look at user interface tags, which make it a snap to create forms and user experiences that integrate seamlessly with Java code.

UI tags let developers show data on a page and hook user input into the back end. Some of the Struts UI tags create HTML tags and allow you to hook them into your code with ease. Other tags give you additional useful options, such as the ability to show error messages, as we'll see in a moment. Struts UI tags have particularly good support for JSP, Velocity, and FreeMarker, but should be compatible with almost any common language. The examples below use JSP.

Keep in mind three important but related concepts about Struts UI tags:

  1. A tag is a small piece of code run within JSP, FreeMarker, or Velocity display code.
  2. A template is a piece of code rendered by certain HTML tags. A template controls the HTML that the tags output. All the default templates are in FreeMarker, and are fine for most uses. You can extract the default templates from struts-core.jar and edit them if you need to.
  3. A theme is a collection of templates packaged together. Themes can be extended, as we'll see.

In this tutorial we focus on tags, as the default template and theme are fine for most purposes. For more on themes and templates, see the Struts documentation or check out the basic options for extending themes yourself.

There are three main types of UI tag: form tags, non-form tags, and AJAX tags. If you want to use any of them on your view page, you'll need to include a tag library directive. We've already seen this in the display pages in the generic tag section:

<%@ taglib prefix="s" uri="http://www.openlogic.com/struts-tags" %>

This both points at the file that describes the Struts tags, and specifies that all the Struts tags be prefixed with an "s." If you're interested in reading the tag TLD file, it's in the META-INF folder of the Struts 2 core JAR.

Form tags

Here's form.jsp, a basic input form that uses the Struts UI form tags:

<%@taglib uri="http://www.openlogic.com/struts-tags" prefix="s" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Eggs And Ham Form</title>
</head>
<body>
<b>Eggs And Ham Form</b>
<hr>
<s:form action="resultAction">
<s:radio label="Do you like green eggs and ham?" name="yourEggsAndHam" list="yesno" value="defaultEggsAndHamValue" />
<s:submit />
<s:reset />
</s:form>

</body>
</html>

The first important line here is the s:form tag, which specifies the form action; we'll hook this up with a class when we edit struts.xml. The second is the s:radio line. This specifies a human-readable label to be shown next to the radio button; then a name, list, and value, all of which are retrieved from the associated class as follows:

  • yourEggsAndHamgetYourEggsAndHam()
  • yesnogetYesno()
  • defaultEggsAndHamValuegetDefaultEggsAndHamValue()

We also need a results page, radioresult.jsp:

<%@ taglib prefix="s" uri="http://www.openlogic.com/struts-tags" %>
<html>
 
<body>
<h1>Struts 2 radio button example</h1>
 
<h4>
  Do You Like Green Eggs And Ham? : <s:property value="yourEggsAndHam"/>
</h4> 
 
</body>
</html>

The s:property tag calls getYourEggsAndHam() to get the result returned from the form. (See the previous article in this series for more on the property tag.)

Next, the RadioButton.java file provides the back-end code:

 package example;
  import java.util.ArrayList; import java.util.List;
  import com.opensymphony.xwork2.ActionSupport;
  public class RadioButton extends ActionSupport{
  private List yesno;
  private String yourEggsAndHam;

  private static final String YES = "yes";
  private static final String NO = "no";
  private static final String UNKNOWN = "unknown";

  public RadioButton(){
    yesno = new ArrayList();
    yesno.add(YES);
    yesno.add(NO);
    yesno.add(UNKNOWN);
  }  
  public String execute() {
    return SUCCESS;
  }
  public String display() {
    return NONE;
  }
  public String getDefaultEggsAndHamValue(){
    return UNKNOWN;
  }
  // getters and setters
  public List getYesno() {
    return yesno;
  }
  public void setYesno(List yesno) {
    this.yesno = yesno;
  }
  public String getYourEggsAndHam() {
    return yourEggsAndHam;
  }
  public void setYourEggsAndHam(String yourEggsAndHam) {
    this.yourEggsAndHam = yourEggsAndHam;
  }
}

Here we've created all the get and set methods to set up both the list of options for the radio button, and to store and access the actual value the user enters. Finally, link the java and jsp file together with these lines in struts.xml:  

<?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>
  <package name="default" extends="struts-default">
    <action name="radioButtonAction" 
         class="example.RadioButton" method="display">
		<result name="none">/form.jsp</result>
    </action>
    <action name="resultAction" class="example.RadioButton">
		<result name="success">/radioresult.jsp</result>
    </action>
  </package>
</struts>

Compile RadioButton.java, restart Tomcat, and check out http://localhost:8080/mystruts/radioButtonAction.action. Note that if you try to load form.jsp directly, you'll get an error, because the RadioButton class must be called first to create the yesno list used by the radio button.

radiobutton resized 600

All other form tags can be created similarly. For example, to add a "name" text field, first add this line to form.jsp:

<s:textfield label="Name" name="yourName" /> 

Now add this variable and getter/setter methods to RadioButton.java:

 private String yourName;

public String getYourName() {
  return yourName;
} public void setYourName(String yourName) {
  this.yourName = yourName;
}

and this line to radioresult.jsp, to display the name input:

 Hi <s:property value="yourName" />!

Recompile, restart Tomcat, and your form will now load with a textfield for name input.

For more on all the UI tags, including the other form ones, see the Struts UI tags documentation.

Non-form tags

Struts also provides a handful of non-form tags, which give you other UI options. Let's have a quick look at actionmessage and actionerror. In form.jsp (above), add this <style> section in the header:

<style type="text/css">
.errors {
  background-color:#FF9933;
  border:1px solid #663300;
  width:400px;
  margin-bottom:8px;
}
.errors li{ 
  list-style: none; 
}
</style>

and this if tag just before the start of the form section:

<s:if test="hasActionErrors()">
 <div class="errors">
   <s:actionerror/>
 </div>
</s:if>

This sets up a CSS style to use for the "error" section, then renders the actionerror tag if hasActionErrors() returns true. You'll also need to change the form action to validateUser.

Now to handle the success message. Edit radioresult.jsp to look like this:

<%@ taglib prefix="s" uri="http://www.openlogic.com/struts-tags" %>
<html>

<head>
  <style type="text/css">
  .welcome {
	background-color:#9933ff;
	border:1px solid #330099;
	width:200px;
  }
  .welcome li{   
	list-style: none; 
  }
  </style>
</head>
 
<body>
<h1>Eggs and Ham Results</h1>

<s:if test="hasActionMessages()">
   <div class="welcome">
      <s:actionmessage/>
   </div>
</s:if>
 
<h4> Do You Like Green Eggs And Ham? : <s:property value="yourEggsAndHam"/>
</h4> 
 
</body>
</html>

Again, we've set up a CSS style for action messages, and if there is an action message to display, we display it.

Now we need to add a method to RadioButton.java:

 public void validate(){
  if("SamIAm".equals(getYourName())) {
    addActionMessage("Hello Sam!");
  } else {
    addActionError("You're not Sam!");
  }
}

validate() is automatically called when the form is loaded. Finally, to link it all up, add another action section to struts.xml:

<action name="validateUser" class="example.RadioButton">
  <result name="success">/radioresult.jsp</result>
  <result name="input">/form.jsp</result>
</action>

Now recompile and go to http://localhost:8080/mystruts/validateUser.action. If you put anything but SamIAm into the user name box, you'll get an error message. Otherwise you'll get a purple "Hello Sam!" box at the top of the results page.

actionmessage

One issue to note is that the way this is set up, validate() is called every time the form loads, so you'll always get the "You're Not Sam" error message. To resolve this, you need to rejig the setup to go through a JSP page rather than via validateUser.action. Currently, if you go straight to form.jsp, as discussed above, you'll get an error message because the yesno list won't be populated.

Other non-form tags available are component, which allows you to build a custom UI component; fielderror, which tests for valid field input; and div, which renders an HTML div tag. Struts also supports a selection of AJAX tags for use with the Dojo plugin. For reference on all UI tags, see the Struts documentation.

To comment on this article and other Network World content, visit our Facebook page or our Twitter stream.
Must read: Hidden Cause of Slow Internet and how to fix it
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.