BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Migrating to Struts 2 - Part III

Migrating to Struts 2 - Part III

This item in japanese

In this final part of the series, we will complete the transformation of the application by migrating the user interface from Struts to Struts2. In part 1 we looked at the high level architecture and basic diffferences between Struts and Struts 2 apps. In part 2 we started converting a real application including actions and configuration.

From a high level, many of the tags in Struts2 are going to look very similar to those that are present in Struts. There are tags for logic, tags to present data from beans, and tags that assist with forms and populating bean data into specific fields. It is only when you take a closer look, that the differences become apparent.

The differences allow the framework to provide features such as:

  • JSP tags being available to different view technologies as first class objects - traditionally, a tag library was only available to JSP. Struts2 takes the approach that all view technologies - JSP, velocity, Freemarker, etc. - should all be first class citizens, and have available to them the objects that will make developing web applications easier.
  • Themes - themes can be provided on a global or individual basis to tags.

These features are available because of the approach taken in architecting the user interface layer.

The User Interface Architecture

Most readers should be familiar with the model-view-controller pattern. It is the basis for both the Struts and Struts2 frameworks. Struts2 incorporates this pattern in another capacity - as the basic of the user interface architecture.

From a high level, this is what it looks like:


Model - the model is extended from the Component base class. The model in the UI architecture has additional responsibility. As well as being an implementation-independent container of data, it provides information on how to render itself - the view - by specifying the templates that are used.

View - the final HTML is generated by Freemarker templates. Normally, it would be the Java code in the taglibs that would provide any necessary logic and write the HTML code to the output stream. By allowing a templating language to take over this function, additional flexibility is achieved.

TIP: Struts2 provides multiple themes with the deployment, by default the "xhtml" theme is used when rendering tag views. The "xhtml" theme provides features for form elements such as layouts using tables, validation message rendering and label / value columns. As well, themes for "css_xhtml" (uses CSS layout rather than table layout), "simple" (with no additional features - just the basic HTML tag rendering) and "ajax" (for Ajax-enabled tag rendering) are available. Any of these can be used in your view code by specifying a value for the "theme" attribute.

Additionally, entirely new themes can be created by developers without the need for a custom framework compilation. This is outside the scope of this article, but further information can be found on the Struts2 wiki.

Controller - for each of the rendering languages that wish access to the taglibs, a new controller object needs to be provided. By default, Struts2 provides the implementations of AbstractDirective (for Velocity), TagModel (for Freemarker) and ComponentTagSupport (for JSP). This allows tag library functionality that once one only available in JSP, to become a first class citizen in other view technologies.

All of this might seem a little abstract at the moment, but as we start discussing the tags in more detail, the practical application will become apparent. But now, it's time to look at some code.

Converting the JSP's

Let's start with the add JSP. Here's what the Struts version looks like:

<html>
<head><title>Add Blog Entry</title></head>
<body>
<form action="save.action" method="post">
Title: <input type="text" name="title" /><br/>
Entry: <textarea rows="3" cols="25" name="entry"></textarea> <br/>
<input type="submit" value="Add"/>
</form>
</body>
</html>

As you may have noticed, this is a pure HTML page. In fact, we could have called it add.html.

Here's the Struts2 version:

<%@ taglib prefix="s" uri="/WEB-INF/struts-tags.tld" %>

<html>
<head><title>Add Blog Entry</title></head>
<body>
<s:form action="save" method="post" >
<s:textfield label="Title" name="title" />
<s:textarea label="Entry" name="entry" rows="3" cols="25" />
<s:submit value="Add"/>
</s:form>
</body>
</html>

We are using JSP, so the first line is the definition of the tag library (we won't include this in the remaining code). The file struts-tags.tld defines the tags that are available, and has been placed in the WEB-INF directory. This file was originally extracted from the "struts2-core-2.0.0-SNAPSHOT.jar" file.

Following through the Struts example, we see that the remaining changes are focused around the HTML tags. The form tag becomes s:form, the textarea becomes s:textarea, and the input tag becomes either s:textfield or s:submit. Whenever possible, the Struts2 tag names will match the HTML equivalent. The input tag is different - rather than adding the type attribute, the type becomes the name of the tag itself.

Using the Struts2 tags, we can see that the code is a little cleaner and easier to read. In the s:form tag the value of the action attribute becomes "save" rather than "save.action". The tag handles adding the extension, along with the web application context. Additionally, if it is needed, there is a namespace attribute to supply additional path information - which the tag also will incorporate into the final HTML form tag markup that is rendered.

The other change is the presence of an additional attribute label. In the Struts2 tags, the text for each of the form elements label becomes part of the tag itself, rather than externally specified. Why does this matter? The answer lies in the rendering of the tags. At the beginning of the article we spoke about the UI architecture, and how the model can render itself. If you do a "view source" on the HTML that the Struts2 add.jsp renders, you will notice that the form and all the elements are within table tags. The label is placed in one column of the table, and the input or textarea HTML tag in the other column. The default "xhtml" theme is providing us with additional layout formatting.

Because this is the add page, there is one final thing to mention. The value of the name attribute determines which field on the action or the model that the user entered value will be set. So if the name is title, make sure you have a setTitle(...) method.

The view.jsp illustrates another commonly used tag - one that renders data values.

The Struts View JSP:

<html>
<head><title>View Blog Entry</title></head>
<body>
Id: <c:out value="${requestScope.blog.id}" /><br/>
Title: <c:out value="${requestScope.blog.title}" /><br/>
Entry: <c:out value="${requestScope.blog.entry}" /><br/>
Updated: <fmt:formatDate
value="${requestScope.blog.created.time}" pattern="MM/dd/yyyy"/><br/>
<br/>
<a href="list.action">Back to List</a> |
<a href="edit.action?id=<c:out value="${requestScope.blog.id}"/>">Edit</a>
</body>
</html>

The Struts2 View JSP:

<html>
<head><title>View Blog Entry</title></head>
<body>
Id: <s:property value="id" /><br/>
Title: <s:property value="title" /><br/>
Entry: <s:property value="entry" /><br/>
Updated: <s:property value="created.time" /><br/>
<br/>
<s:url id="viewUrl" action="list" />
<s:a href="%{viewUrl}">Back to List</s:a> |

<s:url id="editUrl" action="edit" >
<s:param name="id" value="%{id}" />
</s:url>
<s:a href="%{editUrl}" >Edit</s:a>
</body>
</html>

In JSTL the value attribute of the c:out tag provides data to be rendered, which can be static or dynamically evaluated. An expression is denoted by using the delimiters "${" and "}". In the view JSP we want to access object instances that have been placed in the HTTP request scope, this is achieved by starting the expressions with "requestScope". Once the scope has been provided, the path through the object graph is determined using dot notation.

SIDEBAR: Dot notation is an easy way to navigate the path through an object graph. Instead of using the Java code "getPerson().getAddress().getPostcode()" a much simpler "person.address.postcode" is used.

The fmt:formatDate tag is similar to the c:out tag, the difference being that c:out would render the time in milliseconds where the fmt:formatDate tag displays the data in a more user friendly way.

SIDEBAR: Using JSTL is just one way that data could have been made available in the JSP's. Other possibilities include using the JSP tags directly (i.e. jsp:useBean and jsp:getProperty) and to use the Struts Taglib tag library. Like the Struts2 tag library, the Struts Tablib tag library provides additional abstractions around the HTML tags, as well as additional mapping functionality to make implementation easier.

The Struts2 s:property tag is very similar to the c:out tag. It uses an expression language to obtain a value, and the value can also be found by searching through an object graph using dot notation. There are two major differences. The first is that OGNL - Object Graph Navigational Language (http://opensymphony.com/ognl) - is used as the expression language. So not only can you use the dot notation to find values to display, you can also use advanced features such as object method calls, projection and lambda expressions. This is an open source project and developed independently of Struts2.

The second difference is that a scope is not required. This is both an advantage and a disadvantage. Instead of different scopes that the JSP developer needs to explicitly specify, Struts2 has a Value Stack. The Value Stack is just an order of different scopes that is traversed when looking for a value. When looking for a value, if a getter for the field is not found in one scope, the next scope is checked - this continues until either the field is found or all the scopes have been exhausted. The order of the scopes is:

  1. Temporary Objects - these are objects that are created in the JSP page (we will see an example soon with the s:url tag), or they are objects created by tags that have short lives (such as the current object during a loop over a collection).
  2. The Model Object - if model objects are being used, they are checked next (before the action).
  3. The Action Object - this is the action that has just been executed. Hence, without explicitly placing the action in a session or request scope, you will still have access to its data.
  4. Named Objects - these objects include #application, #session, #request, #attr and #parameters and refer to the corresponding servlet scopes.

The advantage is clear - each scope, in turn, is checked for the field that you are after. However, if you have both a model object and action with the same field name (set's say "id"), then problems can occur. If you want the models value the correct result will be returned - but if you want the actions value, you will be returned the models value, as the model scope precedes the action scope. The solution is to provide a qualifier determining where in the stack you want to retrieve the "id" field - in this example "[1].id" would retrieve the value from the action. More information can be found online at http://cwiki.apache.org/WW/ognl-basics.html.

The last piece is the HTML a tag. From our knowledge of JSTL we see that the Struts JSP simply uses a standard HTML a tag, with a JSTL c:out tag to provide the id of the blog that is to be edited. The Struts2 implementation is a little more complex. Here it is again:

<s:url id="editUrl" action="edit" >
<s:param name="id" value="%{id}" />
</s:url>
<s:a href="%{editUrl}">Edit</s:a>

The first tag, s:url, generates the URL that we are going to use. It does this the same way as the s:form tag does, using attributes for action (shown) and namespace (not shown). There is also an attribute for id. This is important as the s:url tag places the generated URL in the Temporary Object scope under the value specified in the id attribute. To add name-value pairs to the URL (the "?user=bob" part), the s:param tag is used.

SIDEBAR: Why can't we just use the s:property tag in the HTML a tag? The answer is that you can. The benefit of the above approach is that the URL generated is consistent across the application.

An advanced feature of Struts2 is being able to change the URL that calls actions. Instead of a standard URL such as "/listUser.action?id=4", you can swap in a new ActionMapper implementation to make the URL more friendly, perhaps more Ruby On Rail such as "/user/4/list". In order to take advantage of a change like this, it is beneficial to have all code generate URL's in a standard manner.

The s:a tag duplicates the HTML a tag functionality, the difference being that the value of the href attribute can be obtained from the Value Stack. In our case we want to obtain the value of the generated edit URL. You may have noticed that both the s:param and the s:a tags both use delimiters - "%{" and "}" where the s:property did not. When a tag is expected to always pull a value from the Value Stack (the s:property tag), delimiters aren't required. But when the value could be static text, values from the Value Stack, evaluated expressions or a combination of any of these options (the s:param and the s:a tag), then the delimiters are required. But don't worry - if you put in the delimiters and they aren't needed, Struts2 will simply remove them.

So far we've looked at entering form data, and viewing information entered in a form. Next is editing the form data. This is going to very similar to the add.jsp code - there will be a HTML form present, as well as HTML input fields. The difference is that we will need some additional tags to display the current information, and we will need a way to tell the action which record we are editing.

Here is the Struts Edit JSP:

<html>
<head><title>Update Blog Entry</title></head>
<body>
<form action="update.action" method="post">
<input type="hidden" name="id"
value="<c:out value="${requestScope.blog.id}" />" />
Id: <c:out value="${requestScope.blog.id}" /><br/>
Title: <input type="text" name="title"
value="<c:out value="${requestScope.blog.title}" />"/><br/>
Entry: <textarea rows="3" cols="25" name="entry">
<c:out value="${requestScope.blog.entry}" /></textarea><br/>
Updated: <fmt:formatDate
value="${requestScope.blog.created.time}" pattern="MM/dd/yyyy"/><br/>
<input type="submit" value="Update"/>
</form>
</body>
</html>

The Struts2 Edit JSP:

<html>
<head><title>Update Blog Entry</title></head>
<body>
<s:form action="update" method="post" >
<s:hidden name="id" value="%{id}" />
<tr>
<td align="right">Id:</td>
<td><s:property value="id" /></td>
</tr>
<s:textfield label="Title" name="title" value="%{title}" />
<s:textarea label="Entry" name="entry" value="%{entry}" rows="3" cols="25" />
<tr>
<td align="right"> Updated:</td>
<td><s:property value="created.time" /></td>
</tr>
<s:submit value="Update"/>
</s:form>
</body>
</html>

This is exactly what we expect. The input HTML tag has an additional attribute value, with the actual value being a c:out tag displaying the current contents for the field, and the textarea HTML tag contains a c:out tag between it's opening and closing tags. The information on the record being edited is communicated to the next action via a hidden HTML tag. This also contains a c:out tag to provide the "id" value of the edited record.

The Struts2 version is even more similar to edit.jsp. Each of the input tags has an additional value attribute, similar to their HTML counterparts, using the delimiters (as the value could be static) and the Value Stack (as described above). There is also a s:hidden tag, which duplicates the hidden HTML tag - as we would expect.

The awkward part of this JSP is that some of the fields (id and updated) require HTML tag information to render them correctly into the theme provided by Struts2, and some do not. There are a couple of solutions to this - the first is to use the "simple" theme and to provide all the layout information within the JSP; the other is to create a new template for the s:input tag that only allows the data to be viewed and not modified. I will leave this as an exercise for the reader.

The final JSP is the list JSP. With this JSP we are introducing a new category of tag libraries that provide logic. This is the only new element being introduced, and we will be combining it with the data rendering tag libraries already discussed.

The List JSP:

<html>
<head><title>List Blogs</title></head>
<body>
My Blogs:<br/> <c:forEach var="blog" items="${requestScope.bloglist}">
<a href="view.action?id=<c:out value="${blog.id}"/>">
<c:out value="${blog.title}"/></a>
[ Updated <fmt:formatDate value="${blog.created.time}" pattern="MM/dd/yyyy"/> ]
(<a href="remove.action?id=<c:out value="${blog.id}"/> ">remove</a>)
<br/>
</c:forEach>
<a href="add.action">Add a new entry</a>
</body>
</html>

The Struts2 List JSP:

<html>
<head><title>List Blogs</title></head>
<body>
My Blogs:<br/>
<s:iterator value="bloglist" >
<a href="view.action?id=<s:property value="id"/>"><s:property value="title"/></a>
[ Updated <s:property value="created.time"/> ]
<s:url id="removeUrl" action="remove" >
<s:param name="id" value="%{id}" />
</s:url>
<s:a href="%{editUrl}" >Edit</s:a>
(<s:a href="%{removeUrl}">remove</s:a>)
<br/>
</s:iterator>
<s:url id="addUrl" action="add" >
<s:a href="%{addUrl}">Add a new entry</s:a>
</body>
</html>

The tag in JSTL is the c:forEach tag, which has two attributes - the var attribute that provides the name that the current element in the collection can be references as, and the items attribute that provide the collection to be iterated over. As we expected, the c:out tags enclosed within the c:forEach tag all start with "blog" so they refer to the current element.

Similarly, in the Struts2 implementation, there is a s:iterator tag. This functions exactly the same as the JSTL c:forEach tag, however, you may have noticed that there is no attribute provided to reference the current element from the collection. The reason lies in the Value Stack again - the current element is placed on the top of the value stack in the Temporary Objects scope, and it can be accessed via the s:property tag without a specific object id. If you feel safer providing an object id, there is an id attribute on the s:iterator tag that works like the var attribute on the c:forEach tag.

Simplifying the Actions

In the last article we discussed the action in detail. You might remember that the last step in all of the action methods was to place the Blog instance in the HttpServletRequest. However, we didn't prepend "#request" to values in the s:property tags.

You should already know why "#request" isn't prepended to the value (the model and the action are placed in the Value Stack). Now, the only thing left to do is to make some simplification changes to the action classes by removing unnecessary code. Specifically, this means that we no longer need to place the Blog in the HttpServletRequest, and the action no longer needs to implement the ServletRequestAware interface.

The same changes need to be made for the ListBlogsAction action, however, as the ListBlogsAction doesn't use model objects, we also need to add a getBloglist() method to the action.

The full source code can be found in an attachment to this article, and the changes to the action classes can be more closely examined there.

Wrap-Up

We've covered a lot in this article, from both a design perspective and an implementation perspective, but we've also had to take a few short cuts. In particular, there was not enough time to devote to an extensive review of all the tags available. The tags in Struts2 are broken down into four categories: control tags, data tags, form tags, and non-form UI tags. Further information on all of these can be found at the Struts2 tag reference page http://struts.apache.org/WW/tag-reference.html.

As well as tags, there is an extensive list of features that we could have talked about. Here are a few of them. I will leave it to you to research those you find interesting:

  • Validation - with Struts2 you can provide validation code in the class or by using a declarative validation framework that works against the action class or the model class. There is also Ajax-based validation available. For further reading, see Zarar Siddiqi article at java.net - http://today.java.net/pub/a/today/2006/01/19/webwork-validation.html.
  • Internationalization - like its predecessor, Struts2 has strong internationalization features built into the actions, validation, messages, and tag libraries.
  • Ajax Support - there is an entire theme build to provide Ajax functionality, as well as ways to return XML and JSON responses rather than HTML page fragments.
  • Results / Result Types - customizing the results is easy, and allows you to result charts, graphs, JSON, XML or anything else you can imagine.
  • Annotations - to make configuration easier, annotations and "convention over configuration" changes are being made. The goal to eventually remove the need for XML configuration for good.

This brings us to the end of the series. By now you should understand the Struts2 architecture (both the overall and the user interface architecture); be able to explain the differences in request processing; understand how to configure a Struts2 application; and know how to combine actions and JSP's.

With a background in Struts, and the information you now have from this series of articles on Struts2, you should be well on your way to migrating complex application as well as starting new Struts2 projects from scratch.

About the author

Ian Roughley is a speaker, writer and independent consultant based out of Boston, MA. For over 10 years he has been providing architecture, development, process improvement and mentoring services to clients ranging in size from fortune 10 companies to start-ups. Focused on a pragmatic and results-based approach, he is a proponent for open source, as well as process and quality improvements through agile development techniques.

Rate this Article

Adoption
Style

BT