Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Apache Struts - From Novice To Professional (2006)

.pdf
Скачиваний:
57
Добавлен:
17.08.2013
Размер:
11.68 Mб
Скачать

188

C H A P T E R 1 4 T I L E S

We want the existing form in both JSPs to be used to deliver keyword search into our Find utility.

If the user clicks Find, the form data is used as keywords. A list of contacts that matches the query appears. Each contact is an HTML link.

If the user clicks on a contact link, the form populates with the contact’s data. If the user clicks Submit, the form data is interpreted as an update to the contact information.

If the user just fills in the form and clicks Submit instead of Find, the form data is interpreted as a new entry.

Figure 14-6 shows the placement of the Find facility within the full.jsp and mnc.jsp pages.

Figure 14-6. Placement of the Find facility within the existing JSP pages

Notice that the form now has two submit buttons: one to submit form data (the “true” submit button) and another to submit the keyed-in data as a search query (the Find button).

The best way to tackle this is to use the LookupDispatchAction technique (see Chapter 17). Please read that the section on LookupDispatchAction before proceeding.

This lab also makes use of Lisptorq-generated Model classes, so be sure to read the relevant sections in Appendix A first.

C H A P T E R 1 4 T I L E S

189

Step 1: Set Up Tiles

1.Put in the plug-in section for Tiles on struts-config.xml. Remember to put in the plug-in section at the end of the file. Call the Tiles definitions file tiles-def.xml.

2.Tiles uses a tag library called struts-tiles.tld. Declare this in web.xml.

Step 2: Write the Controller

The class ContactPeer has a find() function:

public static Scroller find(Contact query)

You will need this function to perform searches based on a given Contact.

Now, the relevant Controller class for the Find tile is FindAction, which is a subclass of net.thinksquarded.lilldep.struts.TilesLookupDispatchAction. This base class is used much in the same way as LookupDispatchAction (see Chapter 17), but is specifically for Tiles.

1.Complete the implementation of find() on FindAction, so that it extracts the Contact instance from the given ActionForm. Save a cloned version of this Contact in the current session, under the key JSPConstants.FIND_QUERY. Use Contact.klone(), which clones the Contact.

2.Use ContactPeer.find() to create a Scroller object using this Contact. You should place this Scroller object in the current request, under the key JspConstants. FIND_RESULTS.

3.find() should return null, because navigation is determined by the main handler for the form.

4.Complete the implementation of unknown() on FindAction, so that it checks the session for a Contact, under the key JspConstants.FIND_QUERY. If the Contact exists, then use it to get a Scroller using ContactPeer.find(). Save the Scroller on the current request. unknown() should return null.

5.Implement the function getKeyMethodMap(), which has the same requirements as

LookupDispatchAction.getKeyMethodMap().

6.Use compile.bat to see if your work compiles.

190

C H A P T E R 1 4 T I L E S

I hope you see what we’re doing here. We want to save the query in session scope so that we can view the Find results from page to page. We can’t simply save the Scroller (and use absolute() to reset it each time we need it) because we might change the Contact’s details so that it no longer matches the query.

There are a few subtleties in this step:

Notice that we have to save a clone of the query, and not the query itself. This is because Struts resets the fields on the query object itself. This behavior is part of how Struts works. So, to avoid holding a blanked-out form, we have to clone it.

The unknown() function is called (you can see the behavior from TilesLookupDispatchAction) when the command parameter in the URL points to a function that does not exist on the Tiles Controller (i.e., FindAction). In our case, unknown() will be called when the user clicks Submit instead of Find.

When the full.jsp page is called directly or by other form handlers (e.g., EditContact.do), then the command parameter isn’t present in the URL. This means that the unspecified() function on TilesLookupDispatchAction is called. So, in order for the Find utility to correctly update itself, unspecified() has to call unknown().

Step 3: Put In the Tiles Action Mapping

1.Create a new form handler in struts-config.xml to declare the Tiles controller you just created.

2.Set the parameter attribute to command. This is necessary for TilesLookupDispatchAction to correctly dispatch according to the submit button that was clicked.

3.Set the scope of the form handler to session, in order to match that of the main form.

4.Be sure that your Tiles controller will get a copy of the form submitted from the main page. (See the section “Getting External Form Data” to see how this is done.)

Step 4: Make Changes to ContactAction

Since there are now two submit buttons (Submit and Find), we require ContactAction to process Submit but ignore Find.

C H A P T E R 1 4 T I L E S

191

1.We’ll use LookupDispatchAction to do this, so you’ll have to change the base class of

ContactAction to LookupDispatchAction.

2.Change the name of execute() to save().

3.Because there are now two submit buttons, we can’t rely on Struts to automatically validate the form for us. This means that we have to call the validate function from save() instead. Make the necessary changes to do this, taking care to set validate=false on the associated form handlers declared in struts-config.xml.

4.Implement the function find(), which has the same signature and return type as execute(). This function should replace the form’s Contact with a clean instance and then return the forward called success.

5.Implement getKeyMethodMap().

You also need to add an extra attribute called parameter, whose value is set to command, to the form handlers associated with ContactAction (there are two of them). This required for LookupDispatchAction to correctly dispatch according to the submit button clicked.

Step 5: Write the Tiles JSP

1.Edit find-tile.jsp so that it displays the company name using the Scroller saved on the request by the name JspConstants.FIND. Hint: Use <logic:iterate> and simply iterate through, as you did for listing.jsp. Remember to check for a null Scroller.

2.Make a link to EditAction for each company name, as you did in listing.jsp in Chapter 13.

3.You get extra credit if you can get the background of the company name link to change color when it’s clicked (no JavaScript solutions—use Struts).

Step 6: Write the Tiles Definition

Add a new definition in the Tiles definitions file, tiles-def.xml. The definition should do the following:

Provide a unique name to the definition.

Link the Tiles form handler in step 2 to the Tiles JSP in step 4.

192

C H A P T E R 1 4 T I L E S

Step 7: Put In the Find Tile

Now, you need to put the Find tile in your JSPs. We’ll start with full.jsp:

1.Look at the layout specs (Figure 14-6), and put in a table with two cells. One cell will hold the existing data entry panel, and the other (on the right) will hold the Find button and the results window.

2.Put in a Find button (look up the key in Application.properties!), which is an

<html:submit>.

3.You need to add property="command" to the new Find button as well as the existing Submit button.

4.Put in the taglib declaration for the Tiles tag library.

5.Repeat steps 1–3 for mnc.jsp.

Step 8: Deploy and Test

Compile and deploy your webapp. Verify the following:

Does the Find utility work? In other words, do you see a list of companies when you use Find?

Does the form populate when you click the company name links?

Does the company name’s background color change when you click on it?

Does the contact update correctly when you make a change?

Does the Find result change when you make an update? For example, if you perform a Find operation for a company name, and then change the company name, does the Find listing change?

Does Find work correctly on both full.jsp and mnc.jsp?

If you use the full/MNC entry forms to enter a new contact, does the database correctly create new contacts?

C H A P T E R 1 4 T I L E S

193

Summary

Tiles is a mechanism for creating layouts and components.

Layouts help streamline a web application’s look and feel.

Tiles components are a way to create reusable GUI components.

C H A P T E R 1 5

■ ■ ■

The Validator Framework

The Validator framework is a Struts plug-in, originally created by David Winterfeldt, that provides a set of generic validations that you can use to run a variety of simple validations. Instead of implementing validate() functions in your ActionForm subclasses, you declare your validations in an XML file.

So, the Validator framework eliminates the need for implementing validate() in your ActionForm subclasses. (You still need your ActionForm subclasses to store form data.)

You reap a number of benefits when you use the Validator framework, as opposed to writing individual validate() functions on your ActionForm subclasses:

Better maintainability: Since the new XML format validations are all placed in one file, you should be able to maintain your validations more easily.

Standardization: Many simple validations require the same checks. For example, both userid and password fields might require checks to ensure they are composed of alphanumerics. If these checks were spread throughout a few validate() functions, standardizing them would be a challenge. As you’ll see, the Validator framework makes it easier for you to standardize your validations.

Correct implementation: Some “simple” validations are quite difficult to implement correctly! A prime example is validating an email address so that it conforms to the RFC-2822 specification (this specification deals with email address formats, among other things). Rather than reinventing the wheel, you can take advantage of validations provided by the Validator framework.

Less code duplication: Similarly, because the Validator framework provides a fairly comprehensive set of validations, you can cut down code duplication. You don’t need to implement your own code to validate things like credit card numbers in each of your web applications. You could argue that it’s possible to write these validations once, put them in a single class, and reuse them for all your apps. True, but this means that new members of your team would have more to learn before they could become productive. In the worst-case scenario, some developers might forget about the shared library of validations and duplicate validations in their validate() functions.

195

196

C H A P T E R 1 5 T H E V A L I D A T O R F R A M E W O R K

Automatic client-side validations: You can automatically generate JavaScript validations on your client by placing a single <html:javascript/> tag in your JSPs. The validator framework will automatically generate the validations for you. This feature of the Validation framework is still underdeveloped; there’s no way for you to specify client-side validation only.

The set of generic validations provided by the Validator framework is quite comprehensive, and you should be able to replace all your validate() functions with XML declarations. However, in case you can’t, it’s possible to run your own custom validations alongside the ones you’ve declared using the Validator framework. It’s also possible to extend the set of standard validations provided by the Validator framework.

Declaring the Validator Plug-in

Like Tiles (see Chapter 14), the Validator framework is independent of Struts. It belongs to the Apache Commons project (see “Useful Links” at the end of this chapter), which aims to create a set of reusable frameworks, the Validator framework being one of them.

Indeed, the Validator framework internals are stored in the commons-validator.jar file that comes with the Struts distribution. This JAR file contains all the Java classes for the framework and the JavaScript to run client-side validations.

To use the Validator framework in your Struts applications, you need to declare it. This means a <plug-in> declaration in the struts-config.xml file (see Listing 15-1).

Listing 15-1. Plug-in Declaration for the Validator Framework in struts-config.xml

<plug-in className="org.apache.struts.validator.ValidatorPlugIn" > <set-property property="pathnames"

value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/> </plug-in>

Notice that it’s ValidatorPlugIn (capital I). A common source of frustration is to use the lowercase “i” as it is in TilesPlugin.

The <set-property> tag sets a single property called pathnames accessible to the plug-in. The value of pathnames is a set of comma-separated files:

validator-rules.xml is a set of declared generic validations for the Validator framework. This file is provided for you in the Struts distribution.

validation.xml links each field in your ActionForm subclass (more precisely, the declared form bean) to one or more validations drawn from those declared in validator-rules.xml. So, validation.xml is where you replace the validate() functions of your ActionForm subclasses.

C H A P T E R 1 5 T H E V A L I D A T O R F R A M E W O R K

197

As the declaration suggests, you need to place both these files in the /WEB-INF/ folder of your web application.

Both validator-rules.xml and validation.xml have the same structure—that is, they are described by the same XML document tag definition (DTD).

Note The DTD is contained in the commons-validator.jar file, which comes with the Struts distribution, under the path /org/apache/commons/resources/validator_1_1_3.dtd.

Since they have the same structure, there’s no reason why you can’t create a single file containing information from both. Of course, this leads to maintenance issues.

Alternatively, you could split your validation.xml file into several files. To use them, just change the plug-in declaration. For example, if you had three validation files, called A.xml, B.xml, and C.xml, then the code Listing 15-1 would be changed to that shown in Listing 15-2. Struts pieces together all four files declared in Listing 15-2 before processing them.

Listing 15-2. Splitting Your validation.xml file into Three Parts

<plug-in className="org.apache.struts.validator.ValidatorPlugIn" > <set-property property="pathnames"

value="/WEB-INF/validator-rules.xml, /WEB-INF/A.xml, /WEB-INF/B.xml, /WEB-INF/C.xml"/>

</plug-in>

Splitting your validation.xml file is useful if your project contains subprojects. It is easier to manage and maintain a few smaller files, each containing forms from a single subproject, than one huge file containing validations for all projects.

Validator DTD Basics

Since the validator-rules.xml and validation.xml files play a central role in the Validator framework, you have to understand their structure. Listing 15-3 is a fragment of the validator DTD, and it describes the major divisions of the validator XML structure.

Listing 15-3. Top Nodes of the Validator XML Structure

<!ELEMENT form-validation (global*, formset*)> <!ELEMENT global (validator*, constant*)> <!ELEMENT formset (constant*, form+)>