Handling web requests

  Windows IT Pro
Windows IT Library
  - Advertise        
Windows IT Pro Logo

  Home  |   Books  |   Chapters  |   Topics  |   Authors  |   Book Reviews  |   Whitepapers  |   About Us  |   Contact Us  |   ITTV  |   IT Jobs

search for  on    power search   help
 






Handling web requests
View the book table of contents
Author: Craig Walls
Published: August 2007
Copyright: 2007
Publisher: Manning Publications
 


13.3 HANDLING REQUESTS WITH CONTROLLERS

If DispatcherServlet is the heart of Spring MVC then controllers are the brains. When implementing the behavior of your Spring MVC application, you extend one of Spring’s controller classes. The controller receives requests from DispatcherServlet and performs some business functionality on behalf of the user.

If you’re familiar with other web frameworks such as Struts or WebWork, you may recognize controllers as being roughly equivalent in purpose to a Struts or WebWork action. One huge difference between Spring controllers and Struts/WebWork actions, however, is that Spring provides a rich controller hierarchy (as shown in Figure 13.6) in contrast to the rather flat action hierarchy of Struts or WebWork.

At first glance, Figure 13.6 may seem somewhat daunting. Indeed, when compared to other MVC frameworks such as Jakarta Struts or WebWork, there’s a lot more to swallow with Spring’s controller hierarchy. In reality, however, this perceived complexity is actually quite simple and flexible.

At the top of the controller hierarchy is the Controller interface. Any class implementing this interface can be used to handle requests through the Spring MVC framework. To create your own controller, all you must do is write a class that implements this interface.

While you could write a class that directly implements the Controller interface, you’re more likely to extend one of the classes lower in the hierarchy. Whereas the Controller interface defines the basic contract between a controller and Spring MVC, the various controller classes provide additional functionality beyond the basics.

The wide selection of controller classes is both a blessing and a curse. Unlike other frameworks that force you to work with a single type of controller object (such as Struts’s Action class), Spring lets you choose the controller that is most appropriate for your needs. However, with so many controller classes to choose from, many developers find themselves overwhelmed and don’t know how to decide.

To help you decide which controller class to extend for your application’s controllers, consider table 13.2. As you can see, Spring’s controller classes can be grouped into six categories that provide more functionality (and introduce more complexity) as you progress down the table. You may also notice from figure 13.5 that (with the exception of ThrowawayController) as you move down the controller hierarchy, each controller builds on the functionality of the controllers above it.

You’ve already seen an example of a simple controller that extends Abstract-Controller. In Listing 13.1, HomePageController extends AbstractController and retrieves a list of the most recent rants for display on the home page. AbstractController is a perfect choice because the homepage is so simple and takes no input.

Basing your controller on AbstractController is fine when you don’t need a lot of power. Most controllers, however, are going to be more interesting, taking parameters and requiring validation of those parameters. In the sections that follow, we’re going to build several controllers that define the web layer of the RoadRantz application by extending the other implementations of the Controller classes in Figure 13.6, starting with command controllers.

13.3.1 Processing commands

It’s common for a web request to take one or more parameters that are used to determine the results. For instance, one of the requirements for the RoadRantz application is to display a list of rants for a particular vehicle.

Of course, you could extend AbstractController and retrieve the parameters your controller needs from the HttpServletRequest. But you would also have to write the logic that binds the parameters to business objects and you’d have to put validation logic in the controller itself. Binding and validation logic really don’t belong in the controller.

In the event that your controller will need to perform work based on parameters, your controller class should extend a command controller class such as AbstractCommandController. As shown in Figure 13.7, command controllers automatically bind request parameters to a command object. They can also be wired to plug in validators to ensure that the parameters are valid.

Listing 13.3 shows RantsForVehicleController, a command controller that is used to display a list of rants that have been entered for a specific vehicle.

The handle() method of RantsForVehicleController is the main execution method for AbstractCommandController. This method is a bit more interesting than the handleRequestInternal() method from AbstractController. In addition to an HttpServletRequest and an HttpServletResponse, handle() takes an Object that is the controller’s command.

A command object is a bean that is meant to hold request parameters for easy access. If you are familiar with Jakarta Struts, you may recognize a command object as being similar to a Struts ActionForm. The key difference is that unlike a Struts form bean that must extend ActionForm, a Spring command object is a POJO that doesn’t need to extend any Spring-specific classes.

In this case, the command object is an instance of Vehicle, as set in the controller’s constructor. You may recognize Vehicle as the domain class that describes a vehicle from chapter 5. Although command classes don’t have to be instances of domain classes, it is sure handy when they are. Vehicle already defines the same data needed by RantsForVehicleController. Conveniently, it’s also the exact same type needed by the getRantsForVehicle() method of RantService. This makes it a perfect choice for a command class.

Before the handle() method is called, Spring will attempt to match any parameters passed in the request to properties in the command object. Vehicle has two properties: state and plateNumber. If the request has parameters with these names, the parameter values will automatically be bound to the Vehicle’s properties.

As with HomePageController, you’ll also need to register RantsForVehicleController in roadrantz-servlet.xml:
<bean id="rantsForVehicleController"
     class="com.roadrantz.mvc.RantsForVehicleController">
  <property name="rantService" ref="rantService" />
</bean>
Command controllers make it easy to handle requests with request parameters by binding the request parameters to command objects. The request parameters could be given as URL parameters (as is likely the case with RantsForVehicleController) or as fields from a web-based form. Although command controllers can process input from a form, Spring provides another type of controller with better support for form handling. Let’s have a look at Spring’s form controllers next.

13.3.2 Processing form submissions

In a typical web-based application, you’re likely to encounter at least one form that you must fill out. When you submit that form, the data that you enter is sent to the server for processing, and once the processing is completed, you are either presented with a success page or are given the form page with errors in your submission that you must correct.

The core functionality of the RoadRantz application is the ability to enter a rant about a particular vehicle. In the application, the user will be presented with a form to enter their rant. Upon submission of that form, the expectation is that the rant will be saved to the database for later viewing.

When implementing the rant submission process, you might be tempted to extend AbstractController to display the form and to extend AbstractCommandController to process the form. This could certainly work, but would end up being more difficult than necessary. You would have to maintain two different controllers that work in tandem to process rant submissions. Wouldn’t it be simpler to have a single controller handle both form display and form processing?

What you’ll need in this case is a form controller. Form controllers take the concept of command controllers a step further, as shown in Figure 13.8, by adding functionality to display a form when an HTTP GET request is received and process the form when an HTTP POST is received. Furthermore, if any errors occur in processing the form, the controller will know to redisplay the form so that the user can correct the errors and resubmit.

To illustrate how form controllers work, consider AddRantFormController in Listing 13.4.

Although it may not be obvious, AddRantFormController is responsible for both displaying a rant entry form and processing the results of that form. When this controller receives an HTTP GET request, it will direct the request to the form view. And when it receives an HTTP POST request, the onSubmit() method will process the form submission.

The referenceData() method is optional, but is handy when you need to provide any additional information for displaying the form. In this case, our form will need a list of states that will be displayed (presumably in a drop-down selection list). So, the referenceData() method of AddRantFormController adds an array of Strings that contains all 50 U.S. states as well as the District of Columbia.

Under normal circumstances, the command object that backs the form is simply an instance of the command class. In the case of AddRantFormController, however, a simple Rant instance will not do. The form is going to use the nested Vehicle property within a Rant as part of the form-backing object. Therefore, it was necessary to override the formBackingObject() method to set the vehicle property. Otherwise, a NullPointerException would be thrown when the controller attempts to bind the state and plateNumber properties.

The onSubmit() method handles the form submission (an HTTP POST request) by passing the command object (which is an instance of Rant) to the addRant() method of the injected RantService reference.

What’s not clear from Listing 13.4 is how this controller knows to display the rant entry form. It’s also not clear where the user will be taken after the rant has been successfully added. The only hint is that the result of a call to getSuccessView() is given to the ModelAndView. But where does the success view come from?

SimpleFormController is designed to keep view details out of the controller’s Java code as much as possible. Instead of hard-coding a ModelAndView object, you configure the form controller in the context configuration file as follows:
<bean id="addRantController"
     class="com.roadrantz.mvc.AddRantFormController">
  <property name="formView" value="addRant" />
  <property name="successView" value="rantAdded" />
  <property name="rantService" ref="rantService" />
</bean>
Just as with the other controllers, the addRantController bean is wired with any services that it may need (e.g., rantService). But here you also specify a formView property and a successView property. The formView property is the logical name of a view to display when the controller receives an HTTP GET request or when any errors are encountered. Likewise, the successView is the logical name of a view to display when the form has been submitted successfully. A view resolver (see section 13.4) will use these values to locate the View object that will render the output to the user.

Validating form input
When AddRantFormController calls addRant(), it’s important to ensure that all of the data in the Rant command is valid and complete. You don’t want to let users enter only a state and no plate number (or vice versa). Likewise, what’s the point in specifying a state and plate number but not providing any text in the rant? And it’s important that the user not enter a plate number that isn’t valid.

The org.springframework.validation.Validator interface accommodates validation for Spring MVC. It is defined as follows:
public interface Validator {
  void validate(Object obj, Errors errors);
  boolean supports(Class clazz);
}
Implementations of this interface should examine the fields of the object passed into the validate() method and reject any invalid values via the Errors object. The supports() method is used to help Spring determine whether the validator can be used for a given class.

RantValidator (Listing 13.5) is a Validator implementation used to validate a Rant object.

The only other thing to do is to configure AddRantFormController to use RantValidator. You can do this by wiring a RantValidator bean into the AddRantFormController bean (shown here as an inner bean):
<bean id="addRantController"
     class="com.roadrantz.mvc.AddRantFormController">
  <property name="formView" value="addRant" />
  <property name="successView" value="rantAdded" />
  <property name="rantService" ref="rantService" />
  <property name="validator">
    <bean class="com.roadrantz.mvc.RantValidator" />
  </property>
</bean>
When a rant is entered, if all of the required properties are set and if the plate number passes validation, AddRantFormController’s onSubmit() will be called and the rant will be added. However, if RantValidator rejects any of the fields, the user will be returned to the form view to correct the mistakes.

By implementing the Validator interface, you are able to programmatically take full control over the validation of your application’s command objects. This may be perfect if your validation needs are complex and require special logic.

However, in simple cases such as ensuring required fields and basic formatting, writing our own implementation of the Validator interface is a bit too involved. It’d be nice if we could write validation rules declaratively instead of having to write validation rules in Java code. Let’s have a look at how to use declarative validation with Spring MVC.

Validating with Commons Validator
One complaint that we’ve heard about Spring MVC is that validation with the Validator interface doesn’t even compare to the kind of validation possible with Jakarta Struts. We can’t argue with that complaint. Jakarta Struts has a very nice facility for declaring validation rules outside of Java code. The good news is that we can do declarative validation with Spring MVC, too.

But before you go digging around in Spring’s JavaDoc for a declarative Validator implementation, you should know that Spring doesn’t come with such a validator. In fact, Spring doesn’t come with any implementations of the Validator interface and leaves it up to you to write your own.

However, you don’t have to go very far to find an implementation of Validator that supports declarative validation. The Spring Modules project (https:// springmodules.dev.java.net) is a sister project of Spring that provides several extensions to Spring whose scope exceeds that of the main Spring project. One of those extensions is a validation module that makes use of Jakarta Commons Validator (http://jakarta.apache.org/commons/validator) to provide declarative validation.

To use the validation module in your application, you start by making the springmodules-validator.jar file available in the application’s classpath. If you’re using Ant to do your builds, you’ll need to download the Spring Modules distribution (I’m using version 0.6) and find the spring-modules-0.6.jar file in the dist directory. Add this JAR to the <war> task’s <lib> to ensure that it gets placed in the WEB-INF/lib directory of the application’s WAR file.

If you’re using Maven 2 to do your build (as I’m doing), you’ll need to add the following <dependency> to pom.xml:
<dependency>
  <groupId>org.springmodules</groupId>
  <artifactId>springmodules-validation</artifactId>
  <version>0.6</version>
  <scope>compile</scope>
</dependency>
You’ll also need to add the Jakarta Commons Validator JAR to your application’s classpath. In Maven 2, it will look like this:
<dependency>
  <groupId>commons-validator</groupId>
  <artifactId>commons-validator</artifactId>
  <version>1.1.4</version>
  <scope>compile</scope>
</dependency>
Spring Modules provides an implementation of Validator called DefaultBeanValidator. DefaultBeanValidator is configured in roadrantz-servlet.xml as follows:
<bean id="beanValidator" class=
     "org.springmodules.commons.validator.DefaultBeanValidator">
  <property name="validatorFactory" ref="validatorFactory" />
</bean>
DefaultBeanValidator doesn’t do any actual validation work. Instead, it delegates to Commons Validator to validate field values. As you can see, DefaultBeanValidator has a validatorFactory property that is wired with a reference to a validatorFactory bean. The validatorFactory bean is declared using the following XML:
<bean id="validatorFactory" class=
     "org.springmodules.commons.validator.DefaultValidatorFactory">
  <property name="validationConfigLocations">
    <list>
      <value>WEB-INF/validator-rules.xml</value>
      <value>WEB-INF/validation.xml</value>
    </list>
  </property>
</bean>
DefaultValidatorFactory is a class that loads the Commons Validator configuration on behalf of DefaultBeanValidator. The validationConfigLocations property takes a list of one or more validation configurations. Here we’ve asked it to load two configurations: validator-rules.xml and validation.xml.

The validator-rules.xml file contains a set of predefined validation rules for common validation needs such as email and credit card numbers. This file comes with the Commons Validator distribution, so you won’t have to write it yourself—simply add it to the WEB-INF directory of your application. Table 13.3 lists all of the validation rules that come in validator-rules.xml.

The other file, validation.xml, defines application-specific validation rules that apply directly to the RoadRantz application. Listing 13.6 shows the contents of validation. xml as applied to RoadRantz.

If the contents of validation.xml look strangely familiar to you, it’s probably because Struts uses the same validation file XML. Under the covers, Struts is using Commons Validator to do its validation. Now Spring Modules brings the same declarative validation to Spring.

One last thing to do is change the controller’s declaration to wire in the new declarative implementation of Validator:
<bean id="addRantController"
     class="com.roadrantz.mvc.AddRantFormController">
  <property name="formView" value="addRant" />
  <property name="successView" value="rantAdded" />
  <property name="rantService" ref="rantService" />
  <property name="validator" ref="beanValidator" />
</bean>
A basic assumption with SimpleFormController is that a form is a single page. That may be fine when you’re doing something simple such as adding a rant. But what if your forms are complex, requiring the user to answer several questions? In that case, it may make sense to break the form into several subsections and walk users through using a wizard. Let’s see how Spring MVC can help you construct wizard forms.

13.3.3 Processing complex forms with wizards

Another feature of RoadRantz is that anyone can register as a user (known as a motorist in RoadRantz’s terms) and be notified if any rants are entered for their vehicles. We developed the rant notification email in chapter 12. But we also need to provide a means for users to register themselves and their vehicles.

We could put the entire motorist registration form into a single JSP and extend SimpleFormController to process and save the data. However, we don’t know how many vehicles the user will be registering and it gets tricky to ask the user for an unknown number of vehicle data in a single form.

Instead of creating one form, let’s break motorist registration into several subsections and walk the user through the form using a wizard. Suppose that we partition the registration process questions into three pages:
  • General user information such as first name, last name, password, and email address
  • Vehicle information (state and plate number)
  • Confirmation (for the user to review before committing their information)
Fortunately, Spring MVC provides AbstractWizardFormController to help out. AbstractWizardFormController is the most powerful of the controllers that come with Spring. As illustrated in Figure 13.9, a wizard form controller is a special type of form controller that collects form data from multiple pages into a single command object for processing.

Let’s see how to build a multipage registration form using AbstractWizardFormController.

Building a basic wizard controller
To construct a wizard controller, you must extend the AbstractWizardFormController class. MotoristRegistrationController (Listing 13.7) shows a minimal wizard controller to be used for registering a user in RoadRantz. Just as with any command controller, you must set the command class when using a wizard controller. Here MotoristRegistrationController has been set to use Motorist as the command class. But because the motorist will also be registering one or more vehicles, the formBackingObject() method is overridden to set the vehicles property with a list of Vehicle objects. The list is also started with a blank Vehicle object for the form to populate.

Since the user can register any number of vehicles and since the vehicles list will grow with each vehicle added, the form view needs a way of knowing which entry in the list is the next entry. So, referenceData() is overridden to make the index of the next vehicle available to the form.

The only compulsory method of AbstractWizardFormController is processFinish(). This method is called to finalize the form when the user has finished completing it (presumably by clicking a Finish button). In MotoristRegistrationController, processFinish() sends the data in the Motorist object to addMotorist() on the injected RantService object.

Notice there’s nothing in MotoristRegistrationController that gives any indication of what pages make up the form or in what order the pages appear. That’s because AbstractWizardFormController handles most of the work involved to manage the workflow of the wizard under the covers. But how does AbstractWizardFormController know what pages make up the form?

Some of this may become more apparent when you see how MotoristRegistrationController is declared in roadrantz-servlet.xml:
<bean id="registerMotoristController"
     class="com.roadrantz.mvc.MotoristRegistrationController">
  <property name="rantService" ref="rantService" />
  <property name="pages">
     <list>
       <value>motoristDetailForm</value>
       <value>motoristVehicleForm</value>
       <value>motoristConfirmation</value>
       <value>redirect:home.htm</value>
     </list>
  </property>
</bean>
So that the wizard knows which pages make up the form, a list of logical view names is given to the pages property. These names will ultimately be resolved into a View object by a view resolver (see section 13.4). But for now, just assume that these names will be resolved into the base filename of a JSP.

While this clears up how MotoristRegistrationController knows which pages to show, it doesn’t tell us how it knows what order to show them in.

Stepping through form pages
The first page to be shown in any wizard controller will be the first page in the list given to the pages property. In the case of the motorist registration wizard, the first page shown will be the motoristDetailForm page.

To determine which page to go to next, AbstractWizardFormController consults its getTargetPage() method. This method returns an int, which is an index into the zero-based list of pages given to the pages property.

The default implementation of getTargetPage() determines which page to go to next based on a parameter in the request whose name begins with _target and ends with a number. getTargetPage() removes the _target prefix from the parameter and uses the remaining number as an index into the pages list. For example, if the request has a parameter whose name is _target2, the user will be taken to the page rendered by the motoristConfirmation view.

Knowing how getTargetPage() works helps you to know how to construct your Next and Back buttons in your wizard’s HTML pages. For example, suppose that your user is on the motoristVehicleForm page (index = 1). To create Next and Back buttons on the page, all you must do is create submit buttons that are appropriately named with the _target prefix:
<form method="POST" action="feedback.htm">
..
     <input type="submit" value="Back" name="_target0">
    <input type="submit" value="Next" name="_target2">
</form>
When the Back button is clicked, a parameter with its name, _target0, is placed into the request back to MotoristRegistrationController. The getTargetPage() method will process this parameter’s name and send the user to the motoristDetailForm page (index = 0). Likewise, if the Next button is clicked, getTargetPage() will process a parameter named _target2 and decide to send the user to the motoristConfirmation page (index = 2).

The default behavior of getTargetPage() is sufficient for most projects. However, if you would like to define a custom workflow for your wizard, you may override this method.

Finishing the wizard
That explains how to step back and forth through a wizard form. But how can you tell the controller that you have finished and that the processFinish() method should be called?

There’s another special request parameter called _finish that indicates to AbstractWizardFormController that the user has finished filling out the form and wants to submit the information for processing. Just like the _targetX parameters, _finish can be used to create a Finish button on the page:
<form method="POST" action="feedback.htm">
…
    <input type="submit" value="Finish" name="_finish">
</form>
When AbstractWizardFormController sees the _finish parameter in the request, it will pass control to the processFinish() method for final processing of the form.

Unlike other form controllers, AbstractWizardFormController doesn’t provide a means for setting the success view page. So, we’ve added a getSuccessView() method in MotoristRegistrationController to return the last page in the pages list. So, when the form has been submitted as finished, the processFinish() method returns a ModelAndView with the last view in the pages list as the view.

Canceling the wizard
What if your user is partially through with registration and decides that they don’t want to complete it at this time? How can they abandon their input without finishing the form?

Aside from the obvious answer—they could close their browser—you can add a Cancel button to the form:
<form method="POST" action="feedback.htm">
...
    <input type="submit" value="Cancel" name="_cancel">
</form>
As you can see, a Cancel button should have _cancel as its name so that, when clicked, the browser will place a parameter into the request called _cancel. When AbstractWizardFormController receives this parameter, it will pass control to the processCancel() method.

By default, processCancel() throws an exception indicating that the cancel operation is not supported. So, you’ll need to override this method so that it (at a minimum) sends the user to whatever page you’d like them to go to when they click Cancel. The following implementation of processCancel() sends the user to the success view:
protected ModelAndView processCancel(HttpServletRequest request,
    HttpServletResponse response, Object command,
    BindException bindException) throws Exception {

  return new ModelAndView(getSucessView());
}
If there is any cleanup work to perform upon a cancel, you could also place that code in the processCancel() method before the ModelAndView is returned.

Validating a wizard form a page at a time
As with any command controller, the data in a wizard controller’s command object can be validated using a Validator object. However, there’s a slight twist.

With other command controllers, the command object is completely populated at once. But with wizard controllers, the command object is populated a bit at a time as the user steps through the wizard’s pages. With a wizard, it doesn’t make much sense to validate all at once because if you validate too early, you will probably find validation problems that stem from the fact that the user isn’t finished with the wizard. Conversely, it is too late to validate when the Finish button is clicked because any errors found may span multiple pages (which form page should the user go back to?).

Instead of validating the command object all at once, wizard controllers validate the command object a page at a time. This is done every time that a page transition occurs by calling the validatePage() method. The default implementation of validatePage() is empty (i.e., no validation), but you can override it to do your bidding.

To illustrate, on the motoristDetailForm page you ask the user for their email address. This field is optional, but if it is entered, it should be in a valid email address format. The following validatePage() method shows how to validate the email address when the user transitions away from the motoristDetailForm page:
protected void validatePage(Object command, Errors errors,
    int page) {

  Motorist motorist = (Motorist) command;
  MotoristValidator validator =
       (MotoristValidator) getValidator();
  if(page == 0) {
    validator.validateEmail(motorist.getEmail(), errors);
  }
}
When the user transitions from the motoristDetailForm page (index = 0), the validatePage() method will be called with 0 passed in to the page argument. The first thing validatePage() does is get a reference to the Motorist command object and a reference to the MotoristValidator object. Because there’s no need to do email validation from any other page, validatePage() checks to see that the user is coming from page 0.

At this point, you could perform the email validation directly in the validatePage() method. However, a typical wizard will have several fields that will need to be validated. As such, the validatePage() method can become quite unwieldy. We recommend that you delegate responsibility for validation to a finegrained field-level validation method in the controller’s Validator object, as we’ve done here with the call to MotoristValidator’s validateEmail() method.

All of this implies that you’ll need to set the validator property when you configure the controller:
<bean id="registerMotoristController"
    class="com.roadrantz.mvc.MotoristRegistrationController">
  <property name="rantService" ref="rantService" />
  <property name="pages">
    <list>
      <value>motoristDetailForm</value>
      <value>motoristVehicleForm</value>
      <value>motoristConfirmation</value>
     <value>redirect:home.htm</value>
    </list>
  </property>
  <property name="validator">
    <bean class="com.roadrantz.mvc.MotoristValidator" />
  </property>
</bean>
It’s important to be aware that unlike the other command controllers, wizard controllers never call the standard validate() method of their Validator object. That’s because the validate() method validates the entire command object as a whole, whereas it is understood that the command objects in a wizard will be validated a page at a time.

The controllers you’ve seen up until now are all part of the same hierarchy that is rooted with the Controller interface. Even though the controllers all get a bit more complex (and more powerful) as you move down the hierarchy, all of the controllers that implement the Controller interface are somewhat similar. But before we end our discussion of controllers, let’s have a look at another controller that’s very different than the others—the throwaway controller.

13.3.4 Working with throwaway controllers

One last controller that you may find useful is a throwaway controller. Despite the dubious name, throwaway controllers can be quite useful and easy to use. Throwaway controllers are significantly simpler than the other controllers, as evidenced by the ThrowawayController interface:
public interface ThrowawayController {
    ModelAndView execute() throws Exception;
}
To create your own throwaway controller, all you must do is implement this interface and place the program logic in the execute() method. Quite simple, isn’t it?

But hold on. How are parameters passed to the controller? The execution methods of the other controllers are given HttpServletRequest and command objects from which to pull the parameters. If the execute() method doesn’t take any arguments, how can your controller process user input?

You may have noticed in Figure 13.5 that the ThrowawayController interface is not even in the same hierarchy as the Controller interface. This is because throwaway controllers are very different from the other controllers. Instead of being given parameters through an HttpServletRequest or a command object, throwaway controllers act as their own command object. If you have ever worked with WebWork, this may seem quite natural because WebWork actions behave in a similar way.

From the requirements for RoadRantz, we know that we’ll need to display a list of rants for a given month, day, and year. We could implement this using a command controller, as we did with RantsForVehicleController (Listing 13.3). Unfortunately, no domain object exists that takes a month, day, and year. This means we’d need to create a special command class to carry this data. It wouldn’t be so hard to create such a POJO, but maybe there’s a better way.

Instead of implementing RantsForDayController as a command controller, let’s implement it as a ThrowawayController, as shown in Listing 13.8.

Before RantsForDayController handles the request, Spring will call the setDay() method, passing in the value of the day request parameter. Once in the execute() method, RantsForDayController simply passes day to rantService. getRantsForDay() to retrieve the list of rants for that day. One thing that remains the same as the other controllers is that the execute() method must return a ModelAndView object when it has finished.

Just as with any controller, you also must declare throwaway controllers in the DispatcherServlet’s context configuration file. There’s only one small difference, as you can see in this configuration of RantsForDayController:
<bean id="rantsForDayController"
    class="com.roadrantz.mvc.RantsForDayController"
    scope="prototype">
  <property name="rantService" ref="rantService" />
</bean>
Notice that the scope attribute has been set to prototype. This is where throwaway controllers get their name. By default all beans are singletons, and so unless you set scope to prototype, RantsForDayController will end up being recycled between requests. This means its properties (which should reflect the request parameter values) may also be reused. Setting scope to prototype tells Spring to throw the controller away after it has been used and to instantiate a fresh instance for each request.

There’s just one more thing to be done before we can use our throwaway controller. DispatcherServlet knows how to dispatch requests to controllers by using a handler adapter. The concept of handler adapters is something that you usually don’t need to worry about because DispatcherServlet uses a default handler adapter that dispatches to controllers in the Controller interface hierarchy.

But because ThrowawayController isn’t in the same hierarchy as Controller, DispatcherServlet doesn’t know how to talk to ThrowawayController. To make it work, you must tell DispatcherServlet to use a different handler adapter. Specifically, you must configure ThrowawayControllerHandlerAdapter as follows:
<bean id="throwawayHandler" class="org.springframework.web.
     => servlet.mvc.throwaway.ThrowawayControllerHandlerAdapter"/>
By just declaring this bean, you are telling DispatcherServlet to replace its default handler adapter with ThrowawayControllerHandlerAdapter.

This is fine if your application is made up of nothing but throwaway controllers. But the RoadRantz application will use both throwaway and regular controllers alongside each other in the same application. Consequently, you still need DispatcherServlet to use its regular handler adapter as well. Thus, you should also declare SimpleControllerHandlerAdapter as follows:
<bean id="simpleHandler" class="org.springframework.web.
     => servlet.mvc.SimpleControllerHandlerAdapter"/>
Declaring both handler adapters lets you mix both types of controllers in the same application.

Regardless of what functionality your controllers perform, ultimately they’ll need to return some results to the user. The result pages are rendered by views, which are selected by their logical name when creating a ModelAndView object. But there needs to be a mechanism to map logical view names to the actual view that will render the response. We’ll see that in chapter 14 when we turn our attention to Spring’s view resolvers.

But first, did you notice that all of Spring MVC’s controllers have method signatures that throw exceptions? It’s possible that things could go awry as a controller processes a request. If an exception is thrown from a controller, what will the user see? Let’s find out how to control the behavior of errant controllers with an exception resolver.


13.4 HANDLING EXCEPTIONS

There’s a bumper sticker that says "Failure is not an option: it comes with the software." Behind the humor of this message is a universal truth. Things don’t always go well in software. When an error happens (and it inevitably will happen), do you want your application’s users to see a stack trace or a friendlier message? How can you gracefully communicate the error to your users?

SimpleMappingExceptionResolver comes to the rescue when an exception is thrown from a controller. Use the following <bean> definition to configure SimpleMappingExceptionResolver to gracefully handle any java.lang.Exceptions thrown from Spring MVC controllers:
<bean id="exceptionResolver" class="org.springframework.web.
     => servlet.handler.SimpleMappingExceptionResolver">
  <property name="exceptionMappings">
    <props>
      <prop key="java.lang.Exception">friendlyError</prop>
    </props>
  </property>
</bean>
The exceptionMappings property takes a java.util.Properties that contains a mapping of fully qualified exception class names to logical view names. In this case, the base Exception class is mapped to the View whose logical name is friendlyError so that if any errors are thrown, users won’t have to see an ugly stack trace in their browser.

When a controller throws an Exception, SimpleMappingExceptionResolver will resolve it to friendlyError, which in turn will be resolved to a View using whatever view resolver(s) are configured. If the InternalResourceViewResolver from section 13.4.1 is configured then perhaps the user will be sent to the page defined in /WEB-INF/jsp/friendlyError.jsp.


13.5 SUMMARY

The Spring Framework comes with a powerful and flexible web framework that is itself based on Spring’s tenets of loose coupling, dependency injection, and extensibility.

At the beginning of a request, Spring offers a variety of handler mappings that help to choose a controller to process the request. You are given a choice to map URLs to controllers based on the controller bean’s name, a simple URL-to-controller mapping, the controller class’s name, or source-level metadata.

To process a request, Spring provides a wide selection of controller classes with complexity ranging from the very simple Controller interface all the way to the very powerful wizard controller and several layers in between, letting you choose a controller with an appropriate amount of power (and no more complexity than required). This sets Spring apart from other MVC web frameworks such as Struts and WebWork, where your choices are limited to only one or two Action classes.

All in all, Spring MVC maintains a loose coupling between how a controller is chosen to handle a request and how a view is chosen to display output. This is a powerful concept, allowing you to mix-’n’-match different Spring MVC parts to build a web layer most appropriate to your application.

In this chapter, you’ve been taken on a whirlwind tour of how Spring MVC handles requests. Along the way, you’ve also seen how most of the web layer of the RoadRantz application is constructed.

Regardless of what functionality is provided by a controller, you’ll ultimately want the results of the controller to be presented to the user. So, in the next chapter, we’ll build on Spring MVC by creating the view layer of the RoadRantz application. In addition to JSP, you’ll learn how to use alternate template languages such as Velocity and FreeMarker. And you’ll also learn how to dynamically produce non-HTML output such as Excel spreadsheets, PDF documents, and RSS feeds.



Page: 1, 2



ADS BY GOOGLE SPONSORED LINKS FEATURED LINKS

Maximize your SharePoint Investment – 8 Cities
Discover best practices and tips for both architecting and administering SharePoint. Early Bird Price of $99 through Sept 15th.

Find a new job now on the all new IT Job Hound!
Search jobs, post your resume, and set up job e-mail alerts!

Master SharePoint with 3 eLearning Seminars
Learn how to build a better SharePoint infrastructure and enable powerful collaboration with MVPs Dan Holme and Michael Noel. Register today!

Top Tools for Virtualization Disaster Recovery & Replication
View this web seminar on August 14th to learn about two tools that will result in faster backup and restore with P2V disaster recovery.

SharePointConnections Conference Fall 2008
Don’t miss the premier event for Microsoft IT Professionals in Las Vegas, November 10-13. Register and book your room by August 25 and receive a FREE room night (based on a three night minimum stay).

VMworld 2008 - Sign Up Today!
Join your peers on September 15-18 at The Venetian Hotel in Las Vegas as VMware hosts VMworld 2008, the leading Virtualization event.



Entrust Unified Communications Certs
Secure Exchange 2007 and save 20%. Now through Sept. 2008.

Increase Application Performance
Free White Paper by Editor's Best winner, Texas Memory Systems.

Need to convert between XML, DBs, EDI, and Excel? Try MapForce free!
Drag & drop to transform between popular data formats – get results instantly or generate code.

Microsoft® Tech•Ed EMEA 2008 IT Professionals
Advance your thinking with new ideas and practical real-world solutions at Microsoft’s FIVE day technical infrastructure conference 3-7 Nov., 2008. Register before 26 September 2008 to save €300.

Order Your SQL Fundamentals CD Today!
Learn how to use SQL Server, understand Office integration techniques and dive into the essentials of SQL Express and Visual Basic with this free SQL Fundamentals CD.

Are You Really Compliant with Software Regulations?
View this web seminar that will help you with compliance best practices and check out a management solution to assure that you won’t be in jeopardy of an audit.

Virtualization Congress Oct. 14-16 in London
Don't miss Virtualization Congress, the premiere EMEA conference dedicated to hardware, OS and application virtualization. Oct. 14-16.
Windows IT Pro Home Register FAQ for Windows WinInfo News
Europe Edition About Us Contact Us/Customer Service Media Kit Affiliates / Licensing  
SQL Server Magazine Office & SharePoint Pro Windows Dev Pro IT Job Hound ITTV
IT Library Technical Resources Directory Connected Home Windows Excavator Windows SuperSite 
 
 Windows IT Pro is a Division of Penton Media Inc.
 Copyright © 2008 Penton Media, Inc., All rights reserved. Terms and Use | Privacy Statement | Reprints and Licensing