|
|
STRUTS 2 introduction | struts webapp basics | struts webapp features | practicalities
Last updated: February 2008
Since 2001 Struts has become the de facto standard in the Java
webapp development world. Struts 2 is a major upgrade of Struts. The new
version takes a lot of ideas and code from another Web application framework
called WebWork from OpenSymphony.
|
|
|
introduction For the Struts 2 version of WebOfContacts these technologies were used:
contactsdb. Then
download the WAR
(make sure to retain the .war extension)
from this site
into your Tomcat's webapps directory, and view the application in your browser at
http://localhost:8080/WebOfContactsStruts2/
(log in as admin/admin).
The full source is available for download as an
Eclipse project.
|
|
|
struts webapp basics As in Struts 1, the flow control of the application is defined in an XML file. For Struts 2 it is called struts.xml. JSPs call actions defined in the struts.xml, which in turn load JSPs. For example, there is a link in leftnav.jsp to /contact-list.action. The corresponding action in struts.xml
looks similar to this:
<action name="contact-list"
class="com.oranda.webofcontacts.struts2.actions.ContactAction"
method="list">
<result name="success">/WEB-INF/jsp/listContacts.jsp</result>
</action>
This means that the method list() inside the class
ContactAction will be called, and that if it returns
SUCCESS, the page listContacts.jsp will be displayed.
ContactAction does not have an execute() method,
but it is quite common in Struts 2 as in Struts 1 to have this as a central
"default" method for the action. However, you no longer need to pass in
lots of parameters (request, response, action form, etc). execute
takes no parameters. Objects are accessed through dependency injection. For
instance, if you need to access the request, you have the action
implement ServletRequestAware interface and make the request
an instance variable along with a setter.
Another way in which the architecture has been simplified in Struts 2 is
that there is no longer any need to have an ActionForm
duplicating each domain object. For instance, consider the central entity
in our application:
Contact. This is passed directly into ContactAction
by the framework calling setContact(). Inside the JSP, the
contact is accessed by calling the getContact() method in
ContactAction via tags.
Struts 2 has a new tag library which is
imported like this
<%@ taglib prefix="s" uri="/struts-tags" %>and used for the form controls like this:
<s:textfield required="true" label="First Name" size="12"
name="contact.firstName" value="%{contact.firstName}"/>
For iteration and conditional control, you can also use the
Struts 2 tags; however, you can still stick with JSTL tags if
you are more comfortable with them and package the right JARs
and TLDs. The file
listContacts.jsp shows a mix of Struts 2 and JSTL tags. The
Struts 2 tags are being promoted as better because they
have a more powerful expression language: OGNL rather than EL.
Two possible solutions for page composition
with Struts are Tiles and Sitemesh. They are used
to assemble pages and give an application a consistent look with header,
footer, navigation, etc. included throughout. For the WebOfContacts
application, Sitemesh was selected. Sitemesh is also from OpenSymphony.
The general layout of a page is specified in pageLayout.jsp. It
includes the stylesheet code and HTML markup to include files
like the header, like this:
<table id="page" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2" id="header">
<%@ include file="/includes/header.jsp" %>
</td>
...
Sitemesh recognizes a special file called decorators.xml
where you can specify the files which define the layout:
in this case just one, pageLayout.jsp.
<decorator name="pageLayout" page="pageLayout.jsp">
<pattern>/*</pattern>
</decorator>
The /* pattern means that all pages are served according to
this general template. The JSPs in the application do not need
to be changed -- Sitemesh will parse them and effectively merge
them with the pageLayout.jsp file. This is done by putting
<decorator:head> and <decorator:body>
tags in the pageLayout.jsp which are replaced by the real HTML
generated by the application JSPs.
As in Struts 1, there are different ways you can organize the
architecture of your application. It is
extremely common in Struts 2 to use Spring,
access the data tier via dependency injection, and use Spring's
OpenSessionInView filter to ensure that a Hibernate session is
kept open for the length of a request. However, the Struts 2 version of
WebOfContacts does not use Spring; Spring is dealt with in other versions.
In WebOfContacts Struts 2 version, there is a HibernateAction
which all the main actions subclass rather than subclassing Struts's own
ActionSupport directly. HibernateAction is
responsible for opening and closing the session, and beginning and
committing transactions.
There is a thin service layer whose classes have access to a Hibernate
session and whose methods assume they are inside a valid
Hibernate transaction. A single UI action can potentially call several
service methods within a single transaction. Here is an example of a
service method in ContactServiceImpl:
public List<Contact> getAllContacts() {
return getSession().createQuery(
"from Contact order by priority desc").list();
}
Inside the quotes is Hibernate's generic HQL code which is
translated into SQL by the Hiberate framework for MySQL.
|
|
|
struts webapp features
Struts 2 provides good support for
form validation.
In the same package as ContactAction.java
there is a file ContactAction-validation.xml which is
automatically picked up by the framework to find the rules
which validate the contact form. Struts provides several
types of validators out-of-the-box; beyond saying that
a field is simply required, you can for example specify a regular
expression that the entered value must match. For example here
is a sample rule in ContactAction-validation.xml for phone
numbers:
|
|
|
practicalities How can the webapp be tested? The service layer is independent of the webapp container, and so it can be tested independently -- see the folder testsrc and the package com.oranda.webofcontacts.struts2.service.
The JUnit tests do need to do the work of wrapping calls in Hibernate
sessions/transactions as the Struts actions are not doing it.
In this small application the UI does not have its own test cases.
The StrutsTestCase software does not work with Struts 2 yet and that
has left some people in doubt when migrating from Struts 1 to Struts 2.
Struts heavyweight Ted Husted recommends Selenium as a tool which
runs tests directly in a browser.
How usable is the framework? The
architecture for Struts 2 is cleaner than its predecessor's
meaning your code can be simplified. However, the typical developer
will still run into the usual issues of having to track down JARs
that shouldn't be missing, deal with conflicting classpaths and JNDI
contexts in tools like Eclipse and Tomcat, and interpret error messages
and stack traces that do not necessarily point to the real problem.
The main
Struts documentation is organized as a Wiki and is very useful.
It does not yet answer every question and bug a developer may run into
while developing an application such as this one.
|