Section 19.7. Struts Tags


19.7. Struts Tags

Struts was one of the first frameworks to provide a library of custom JSP tags . The Struts tags provide an amazing array of utilities useful in JSP; also, they provide access to Struts objects so that you don't have to include Java snippets in your pages. Since the introduction of JSTL, the most common practice is to prefer a JSTL tag when its functionality is similar to an equivalent Struts tag. Struts tags are still very handy for integrating the rendering of pages to Struts data structures such as Actions and ActionForms. In general, JSTL and Struts tags cohabitate quite well, with one exception: internationalization. For internationalization, you are advised to stick to JSTL or to Struts, because their strategies for bundling up the internationalized versions are different.

There are too many Struts tags to describe in this chapter; we will focus here on the tags and tag attributes that are used in the code example. If you have never used a tag library, read the discussion of JSTL in Chapter 4 first.

In the next section, we'll look at the core tags for HTML rendering, obtaining bean properties, and forwarding requests to Struts Actions. These tags are in the Struts tag libraries named html, bean, and logic. For each library, you must include a directive at the top of each page that references the particular library, associating it with a prefix of your choosing. (The prefix names html, bean, and logic are conventional, but you may change them to avoid namespace collisions with other tag libraries you might be using.) It is typical to put these directives into an include file that is then included in all of your pages. For instance, in the example code, the list of directives for including Struts tags looks like this (in includes/setup.inc):

 <%@ taglib prefix="html"            uri="http://jakarta.apache.org/struts/tags-html" %> <%@ taglib prefix="bean"            uri="http://jakarta.apache.org/struts/tags-bean" %> <%@ taglib prefix="logic"            uri="http://jakarta.apache.org/struts/tags-logic" %> 

And the inclusion is just this single line:

 <%@ include file="/includes/setup.inc" %> 

19.7.1. Form Handling and Form Tags

What we are going to describe now is the magic by which Struts tags orchestrate the mapping of form fields to bean properties, get those properties validated, and in the case of errors, redisplay those form fields to the user for correction. First the nuts and bolts regarding syntax and tying the various files together.

19.7.1.1. <html:form>

You use the <html:form> tag in your JSP to render an HTML form tag. The layout of your Struts tags for a typical form follows the same structure as an HTML form. Here's a compressed version of the login form from Example 19-2:

 <html:form action="/login" focus="username">   Username: <html:text property="username"/>   Password: <html:password property="password" redisplay="false"/>   <html:submit/> </html:form> 

<html:text>, <html:password>, and <html:submit> map to the obvious HTML tags; more about that in a moment.

Notice the action attribute. For the action attribute, specify a path that is defined for an action mapping in your struts-config.xml file. So in this case, the form data will be posted to the Struts action with the path /login. Here's the action mapping defined in struts-config.xml for the path /login:

 <action path="/login" name="LoginForm" scope="request"         validate="true" input="/login/index.jsp"         type="com.oreilly.jent.struts.library.ui.LoginAction">   <forward name="success" path="/login/success.jsp" redirect="false"/>   <forward name="failure" path="/login/index.jsp" redirect="false"/> </action> 

Notice that the Struts ActionForm to be used is looked up from the struts-config.xml file based on the action mapping. So in this case, the name of the ActionForm to be used is LoginForm, which is defined in struts-config.xml as follows:

 <form-bean name="LoginForm"     type="com.oreilly.jent.struts.library.ui.LoginActionForm"/> 

This level of indirection means that you can change parameters associated with form handling (e.g., the scope of a form) without changing your JSP. Or you might swap in a different ActionForm that provides more sophisticated validation.

The resulting HTML is:

 <form name="LoginForm" method="post"     action="/jent-struts/login.do">   Username: <input type="text" name="username" value="">   Password: <input type="password" name="password" value="">   <input type="submit" value="Submit"> </form> 

The most significant transformation is the rendering of the HTML action attribute with the appropriate context for your application, along with the addition of the file type (specified by you in the Struts servlet parameters in web.xml) that the container will recognize as a request for the Struts servlet.

Now for the magic. The first thing an <html:form> tag does is find the ActionForm object (the form bean) associated with the ActionMapping. If the form bean doesn't exist, it will create it. When the form is submitted, form data will be loaded into the bean and then the validate method will be called (generating an ActionErrors object). If the validation fails, Struts will forward to the page specified for the ActionMapping's "input" attribute. Typically, this is the same page that displayed the original form (though it needn't be). And with the <html:errors> tag, this page can display the errors that were encountered. Meanwhile, since the very same form bean is used, the form will be prepopulated with the invalid values so that the user may correct them.

19.7.1.2. <html:text>, <html:password>, and <html:submit>

Individual HTML form elements can be specified through a matching Struts tag. In the previous example, for instance, the Struts <html:text> tag will be rendered as an HTML input tag with the type attribute set to text. Similarly, the <html:password> tag is rendered as an HTML input tag with type set to password. The value of the property tag ties the particular Struts tag to the property on the form-bean. You can also easily associate a property value with an <html:submit> tag. By this means, you can provide two submit buttons with the same property name but different values, and then, in your Action, differentiate between them. For instance, in the form on /view/addbook.jsp, we define two submit buttons like so:

 <html:submit property="addBookAction" value="Add Book"/> <html:submit property="addBookAction" value="Verify"/> 

On the backend in AddBookAction, we skip adding the book if only the Verify button were pressed:

   public ActionForward execute(ActionMapping mapping, ActionForm form,       HttpServletRequest request, HttpServletResponse response)       throws Exception {     DynaActionForm addBookForm = (DynaActionForm) form;     String addBookAction = addBookForm.getString("addBookAction");     if (!"Verify".equals(addBookAction)) {       String title = addBookForm.getString("title");       String author = addBookForm.getString("author");       String isbn = addBookForm.getString("isbn");       Book book = new Book(title, isbn, author);       getLibrary(  ).addBook(book);       return mapping.findForward("home");     }     return mapping.findForward("addbook");   } 

19.7.1.3. <html:select>, <html:options>, and <html:checkbox>

Struts provides tags that can render all of the standard HTML input widgets. These tags can be enormously convenient because they provide help with iterating over the elements in a Collection to generate the complete HTML. For example, observe the code using <html:select> for generating an HTML <select> tag:

 <html:select property="trackingID" size="10" onchange="submit(  )">    <html:options collection="bookList"                  property="trackingID" labelProperty="title"/> </html:select> 

The surrounding form is bound to the action with path /bookDisplay, which uses the form-bean BookDisplayForm, which is bound to the BookDisplayActionForm, which contains the property TRackingId. (That's a lot of interaction, but you will find that you are conducting this kind of code tracing on a regular basis with Struts.) Based on the user's selection, trackingId will be populated after the form is submitted. To enumerate the books associated with each trackingId, we use the page-scoped variable bookList, which is bound to a Collection of Books. The Struts tag <html:options> takes the reference to the collection, iterates through it, and renders an HTML <option> tag with the value coming from Book.trackingId and the display text coming from Book.title.

Our use of the <html:checkbox> tag is quite simple: when the box is checked, we submit immediately thanks to the JavaScript embedded in the onchange attribute:

 <html:checkbox property="safeModeChange" onchange="submit(  )"/> 

(Tying the checkbox to the form submission provides for some cheap "event handling"; you can also use an <html:checkbox> to represent an ordinary checkbox input.) Then the Action handling the form checks the value of the property associated with the checkbox.

19.7.1.4. <html:multibox>

If you need to render a checkbox whose value is determined by the loop in which the checkbox is enclosed, use an <html:multibox>. Here's an example (simplified version from adminbooks.jsp in the example):

 <c:forEach var="book" items="${library.bookList}">   <html:multibox property="picks" onclick="submit(  )">     <c:out value="${book.trackingID}"/>   </html:multibox> </c:forEach> 

In this code fragment, the JSTL <c:forEach> tag is used to iterate through the individual books. The <html:multibox> tag defines the form-bean property that will be populated when the checkbox is checked. The actual value of each generated checkbox is pulled from the trackingID property of each book in the list. The JSTL <c:out> tag renders the property value of the book bean's trackingID property.

19.7.2. Additional Tags

The additional tags we discuss handle a variety of important functions, including links, errors, and forwards.

19.7.2.1. <html:link>

The <html:link> tag renders an HTML <a> tag. You specify the value of the link using one of the following required attributes: forward, action, href, or page. The forward and action attributes take the names of Struts forwards and actions as their values. Using one of these attributes allows you to update your struts-config.xml file to change the destinations of links without having to change your JSP files. If you use the href attribute, its value is used directly as the value of the generated href attribute. The page attribute provides support for server-relative URIs: the context path and module prefix (if you are using Struts modules) will be automatically added to the value given for this attribute.

Other attributes on the <html:link> tag allow you to specify URL parameters, as well as mappings for all of the standard attributes for the HTML <a> tag.

Here's a simple example of the <html:link> tag, using the forward attribute to specify the target of the link:

 <html:link forward="login">   Log In </html:link> 

If we now browse to this page and view the generated HTML source, we will see this substitution based on information from the struts-config.xml file (assuming you're using the sample config file provided with the example code for this chapter):

 <a href="/jent-struts /login/index.jsp;jsessionid=7A505454F6FC979CE94F5AEA76775BA3">Log In</a> 

The <html:link> tag conveniently utilizes HttpServletResponse.encodeURL( ) from the Servlet API to rewrite the URL, adding the context name (/Jent-Struts-example), the path for the forward (/login/index.jsp), and the standard session ID token and value.

19.7.2.2. <html:errors>

We discussed error handling in our earlier section on the ActionForm class. To recap, validation is conducted in an ActionForm's validate method; when a validation fails, your code adds an ActionMessage to an ActionErrors object. The validate method returns a reference to the ActionErrors object, which Struts then puts into request or session scope (by default, under the key Globals.ERROR_KEY) where you can pick it up in a JSP and display it to your users.

Instead of working your way through the ActionErrors with your own code, you can use the <html:errors> tag to display whatever ActionErrors are available. The display of the errors can be controlled by defining message keys in your message resources file (typically application.properties). The key names and their functions are shown in Table 19-3 (the descriptions are quoted verbatim from the Struts API documentation).

Table 19-3. Key names for <html:errors>

Key

Description

errors.header

Text that will be rendered before the error messages list. Typically, this message text will end with <ul> to start the error messages list.

errors.footer

Text that will be rendered after the error messages list. Typically, this message text will begin with </ul> to end the error messages list.

errors.prefix

Text that will be rendered before each individual error in the list.

errors.suffix

Text that will be rendered after each individual error in the list.


The Struts API documentation suggests extremely plain markup for error formatting, which is a good bet for getting something that looks decent in most contexts. But you can also reference custom styles or invoke any other HTML that will make your errors look pretty. Here are the definitions of these attributes for the sample application:

 errors.header=<div > errors.footer=</div><br> errors.prefix= errors.suffix=<br> 

Each of these values may be overridden by an attribute on the tag (header, footer, prefix, or suffix), but the typical scenario is to define this markup once in the message resources file and then invoke the tag with no attributes. In the sample application, we display errors on the pages that display the login form and the form for adding booksthe invocation of <html:errors> is simply:

 <html:errors/> 

Note that Struts clears out the errors from the previous page (see step 6 in "The RequestProcessor" earlier in this chapter).

19.7.2.3. <logic:forward>

At times, you want a non-Struts JSP to take the user to a page managed by Struts. The classic use for this is to take a request to the application's welcome page (defined in web.xml) and have it handled by Struts. For example, our index.jsp forwards the request to the global forward home:

 <%@ include file="/includes/setup.inc" %> <logic:forward name="home"/> 

The global forward home is bound to the path /home.do which returns home.jsp.

19.7.3. Using the JSTL Expression Language in Struts Tags

Everything you learned in Chapter 4 regarding the JSTL EL can be used in the attributes of Struts tags. In your Struts download in the contrib/struts-el/lib directory, you will find a struts-el.jar file that may be used in place of struts.jar. In your taglibs directives, now define your HTML tags like this:

 <%@ taglib prefix="html-el"     uri="http://jakarta.apache.org/struts/tags-html-el" %> 

Now you can use dynamic expressions as the values of attributes on Struts tags. For example:

 <html-el:link forward="${home}">Return to Home Page</html-el:link> 

In this example, we make the choice of the forward attribute dynamic, based on the value of the home page attribute.



Java Enterprise in a Nutshell
Java Enterprise in a Nutshell (In a Nutshell (OReilly))
ISBN: 0596101422
EAN: 2147483647
Year: 2004
Pages: 269

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net