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

Beginning Apache Struts - From Novice To Professional (2006)

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

268

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

Note We’ll be using Lisptorq-generated Model classes to store and retrieve data from these tables, so be sure to read Appendix A’s section on Lisptorq.

There’s quite a bit to implement, so we’ve broken down this lab into six subparts. The source code answers for this lab (found in the Source Code section of the Apress website, located at http://www.apress.com) are similarly divided into six parts.

Figure 18-1. The navigation button for the Collection facility

Lab 18a: The Main Collect Page

The main Collect page allows users to create, view, and edit collections. Figure 18-2 shows this page with a couple of collections defined. This lab sets up the basic page, and subsequent labs implement the viewing and editing facilities.

1.Complete the implementation of CollectAction to prepare the list of collections to be displayed. (Hint: You need to use the Criteria class to retrieve all Collection data objects stored in the database.) Use an appropriate constant from JSPConstants for an attribute name under which to store the list of Collection data objects.

2.Put in an action mapping so that a link to Collect.do displays the list of collections. The success forward should point to collect.jsp.

3.Complete collect.jsp so that it displays the names of all defined collections. (Hint: The Scroller interface extends Iterator, so you should be able to use

<logic:iterate> with it.)

4.Each collection listed by collect.jsp should have a delete link on its left linked to DeleteCollection.do. This link should pass the collection’s ID as a parameter called id.

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

269

5.Complete the implementation of DeleteCollectionAction so that it deletes the selected collection. (Hint: Refer to Appendix B to see how to retrieve the value of the id parameter from HttpServletRequest.)

6.Put in an action mapping so that DeleteCollection.do maps to

DeleteCollectionAction. success should forward to Collect.do (and not collect.jsp).

Ensure that your work compiles before proceeding.

Figure 18-2. The main Collect page, showing some collections

Lab 18b: The New Collection Page

Each collection has a name by which it is known and a memo for holding the user’s notes. In addition, a collection contains any number of Contacts. In order to bootstrap a collection, the user needs to specify a SQL query:

The queries are SQL-like—for example, postcode<>'' and email like'%mit%' would fetch all contacts with nonblank postcodes and whose email addresses contained the string mit.

Each query results in a list of contacts matching the query string. The user may subsequently add, remove, or edit contacts within the collection.

Figure 18-3 shows the New Collection page.

270

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

Figure 18-3. The New Collection page

Complete the following:

1.Put in a new dynamic form bean called NewCollectionFormBean, with the properties name, query, and memo as Strings.

2.Put in validators (using the Validator framework) to check that the name and query attributes are not blank. Check the message resource file for suitable error messages.

3.Complete the implementation of new-collection.jsp so that it asks the user for the name, query, and memo property values. Remember to put in <html:error> tags so that the user is warned if a validation fails.

4.Complete the implementation of NewCollectionAction to create a new collection. (Hint: Use DynaActionForm’s generic get() to read property values. You also need to know how to run an arbitrary SQL SELECT using a peer object.)

5.Put in an action mapping to create a new collection. success forwards to list-collection.jsp.

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

271

6.Declare a local exception handler on the action mapping to pass to new-collection.jsp if there’s an error. This is exactly the same as declaring a global exception handler (see Chapter 9), except that the <exception> tag appears as a child tag of <action>. Note that the <exception> tag has to come before any <forward> tags.

Lab 18c: The Collection Listing Page

You will now implement functionality to view the contacts in a collection. Figure 18-4 shows the Collection Listing page, after you’ve completed Lab 18d. First, you need to enable listing the collection from the main Collect page:

1.On collect.jsp, make the collection’s name link to ListCollection.do, with the collection’s ID as a parameter.

2.Put in an action mapping for ListCollection.do, linking it with ListCollectionAction. success forwards to list-collection.jsp.

3.list-collection.jsp lists the contacts in a collection, but it needs a Scroller to iterate through all the contacts. Complete the implementation of ListCollectionAction so that the selected Collection is put on the session (see

JSPConstants for a suitable key), thus making it accessible to list-collection.jsp. The reason for putting it on the session rather than the request will become obvious in Labs 18d and 18f. Compile your work before proceeding.

4.NewCollectionAction also forwards to list-collection.jsp, so it also needs to put the newly created Collection on the session. Use the same key as in step 3.

5.Complete list-collection.jsp so that it displays the list of Contacts on a Collection. You should list exactly the same items as the Full Listing page (see Chapter 13). Display the name of the collection prominently at the top of the page. (Hint: You need to use Collection.getContacts().)

Compile, deploy, and test before proceeding. In particular, test that you can

Create a new collection

List a newly created collection

Access the collection listing from the main Collect page

Delete a collection from the main Collect page

272

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

Figure 18-4. The Collection Listing page

Lab 18d: Removing Selected Contacts

We want to add check boxes to the left of each contact’s name (see Figure 18-4) in the collection listing (that is, list-collection.jsp), to allow the user to selectively remove contacts from a collection. In Lab 16 we used a dynamic form with <html:multibox>. We’ll use the same technique now.

One approach is to create a new form (perhaps a dynamic form, following Lab 16), which holds the contacts to be removed from the collection, as well as the ID of the collection on which to perform this action:

<form-bean name="RemoveSelectionFormBean" type="org.apache.struts.action.DynaActionForm">

<form-property name="selected" type="java.lang.String[]" /> <form-property name="collectionId" type="java.lang.String" />

</form-bean>

The latter might be stored as a hidden input field on the listing displayed to the user, while the selected property is populated using the <html:multibox>, as before.

This simple technique has an obvious drawback if you’re worried about security, since a malicious user could manually craft an HTML form that had a collection ID to which he had no access privileges.

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

273

One simple way to prevent this is to store the collection ID on the session object instead of exposing it on the form. This way, a malicious user would have to fake an active session ID in order to gain access to a given collection. This is much more difficult than reading the collection ID embedded in the page’s HTML.

Note One bonus is that we can reuse SelectionFormBean from Lab 16.

We’ll use this approach here. In fact, we’ve had this technique in mind already— remember that in Lab 18c, we asked you to store the Collection instance in the session scope? Well, this is where that comes in handy. We can just use this object to determine the currently selected Collection.

The drawback is that we have to ensure that all entry points to list-collection.jsp must place the Collection onto the current session; otherwise, list-collection.jsp will not display correctly. There are two such entry points—NewCollectionAction and ListCollectionAction—and both have done this already in Lab 18c.

So, all we have to do is the actual work of removing contacts from a collection:

1.Complete RemoveCollectionContactsAction to remove selected contacts from the given collection. You’ll need to interrogate the current session object for the Collection you saved in the previous lab.

2.Put in an action mapping for a path RemoveCollectionContacts.do to link

RemoveCollectionContactsAction and SelectionForm (see Lab 16). Forward to list-collection.jsp, so that the collection’s listing is redisplayed.

Lastly, you need to amend list-collection.jsp so that it allows the user to select and submit contacts for removal:

1.Put in an <html:multibox> whose values are the IDs of the associated Contact.

2.Create an <html:form> that submits to RemoveCollectionContacts.do.

As usual, compile, deploy, and test your changes.

Lab 18e: Adding Selected Contacts

We need to allow the user to add selected contacts to a collection, while she is viewing the collection’s listing (that is, list-collection.jsp). She does this by clicking Add Contacts on the navbar at the top of the page (see Figure 18-4).

274

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

We want the Add Contacts link to display a list of all contacts (displayed by select-contacts.jsp), with check boxes on the left of the company names. The user selects the contacts she wants to add to the current collection and this information gets sent to AddCollectionContacts.do. Figure 18-5 shows the Add Contacts page.

1.Create a new form handler called AddContacts that invokes ListingAction and forwards to select-contacts.jsp.

2.Complete select-contacts.jsp so that it displays a list of Contacts (as in the Full Listing page). The user is allowed to select any number of Contacts from this list to add to the currently selected Collection. Use the <html:multibox> technique you used in Lab 18d. Ensure that your form submits to AddCollectionContacts.do.

3.Complete the implementation for AddCollectionContactsAction so that it adds the selected Contacts to the current Collection.

4.Put in an appropriate form handler to hook up AddCollectionContactsAction with

AddCollectionContacts.do. The form bean associated with AddCollectionContacts is, of course, SelectionFormBean (see Lab 16). AddCollectionContacts should forward to list-collection.jsp.

As usual, compile, deploy, and test your work before proceeding.

Figure 18-5. The Add Contacts page

Note

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

275

Lab 18f: Up and Down a Search

From a collection’s listing page (list-search.jsp), we’d like to edit the contacts in a collection, and navigate with Previous and Next buttons.

That is, we want the collection’s listings to be a list of links (as it was for the Full Listing page in Chapter 13—see also Figure 18-4). If a link was clicked, the contact’s details would be displayed. The user can move up and down the collection, viewing the details of each contact using Next or Previous buttons at the top of the page. Figure 18-6 shows the Contact Editing page. The user can at any point make changes to a contact’s details. Doing so would cause the changes to be saved to the database, and the same contact’s details to be redisplayed.

The main design challenge is accessing a given contact on the collection (when the user clicks the link), then navigating forward/backward along the collection to display other contacts for editing (when the user clicks Next or Previous).

Before reading further, give yourself a few minutes to think of solutions to these problems. (Hint: You will have to look at the source for the Scroller interface.)

The first problem is easily solved, since the Scroller interface has an absolute() function that allows us to go to the required contact on a collection, given the contact’s “offset” on the collection.

Scroller’s absolute() function is so named because concrete Scroller implementations contain a java.sql.ResultSet instance, which also has an absolute() function. Scroller’s absolute() function calls the underlying ResultSet’s absolute() function.

Also, <logic:iterate> exposes an index variable (using the attribute indexId; see Chapter 10), which we can use to label the links on the listing. The absolute() function, along with an offset may be used to navigate up and down the collection’s listing. As we will see, this is simpler than it sounds!

We’ll use DispatchAction (see Chapter 17) here, so be sure you understand how it works before proceeding. Complete the following:

1.Amend list-collection.jsp so that the company name is now a link, pointing to CollectionNav.do&action=go, with a parameter called offset equal to the iterator’s index, and a parameter called id for the contact’s ID.

2.Complete the implementation of CollectionNavAction so that if action=go, it initializes the form (a ContactFormBean) with the Contact determined from the given id parameter. Save the offset parameter on the session under a suitable key.

276

C H A P T E R 1 8 R E V I E W L A B : T H E C O L L E C T I O N F A C I L I T Y

3.Put in an action mapping for the path CollectionNav.do, linking CollectionNavAction and the form bean ContactFormBean. The forward should be to full-collection.jsp. Remember to set the parameter attribute of the action mapping.

4.Complete the implementation of ContactUpdateAction to save the updated contact.

5.Put in an action mapping to handle submission of the form in full-collection.jsp. Reuse ContactForm to hold the contact details. Remember to use session scope so that the Contact will be redisplayed if Submit is clicked.

6.Amend CollectionNavAction to handle action=previous and action=next. These obviously are commands to go up and down the Collection contact list. (Hint: Use the offset saved in CollectionNavAction’s go() function. You can use this offset and the absolute() function to navigate to the right contact.)

Compile, deploy, and test your amendments.

Figure 18-6. The Contact Editing page

Summary

I hope this review lab reinforces some of the concepts you’ve learned in the second part of this book. I also hope you see how easy it is to incrementally build on an existing webapp using Struts.

C H A P T E R 1 9

■ ■ ■

Developing Plug-ins

Plug-ins are a great way to extend the basic functionality of Struts. In previous chapters, you’ve seen plug-ins at work—in Tiles and the Validator framework. In this chapter, I’ll walk you through developing a nontrivial and useful plug-in called DynaForms. Essentially, the DynaForms plug-in brings Tiles-like inheritance to dynamic form beans. I’ll explain in more detail what this means shortly.

The inspiration for this idea comes from an excellent pair of articles: “Adding Spice to Struts,” parts 1 and 2, by Samudra Gupta (see “Useful Links” at the end of this chapter). Samudra’s solution to the problem of implementing an inheritance mechanism for dynamic form beans involves subclassing fundamental Struts classes, primarily ActionServlet. Unfortunately, as Samudra discusses in his article, his solution has a couple of downsides: the inheritance declaration is a little kludgy and limited. If you’re interested in learning more, look up these articles for details.

In this chapter, we’ll take a different route and, I hope, a more scenic one—meaning you get to see more of how Struts works under the hood. We’ll create a plug-in that allows developers to create form beans with inheritance in XML files outside of struts-config.xml.

In order for you to better follow the discussion, it would be helpful to have a copy of the latest Struts sources handy (see “Useful Links” for the download site; I’ll be using release 1.2.7 in this chapter), and have them in a project within Eclipse (or a similar IDE). An IDE like Eclipse (again, see “Useful Links”) is absolutely essential to easily trace function calls, declarations, and class hierarchies. You can do it with Notepad, but it won’t be much fun.

The Task at Hand

Consider the hierarchy of entities shown in Figure 19-1 (a variation on the main example in Samudra’s first article).

277