Section 2.3. Enhancing the Web Application

team bbl


2.3. Enhancing the Web Application

The code that you've seen so far begins to provide much needed organization with distinct models, views, and controllers. In this section, we'll add validation logic, a resolver, and input forms.

These enhancements will add better organization to your code and save you time and effort. Like many MVC frameworks, these classic enhancements make it easier to handle the classic flow of control that you generally get with web applications:


Resolvers

As your application grows, you'll want to refer to each page with a logical name rather than a full path. The resolver manages the details, like the extension and the path, letting you specify these details in your configuration.


Form

These input JSPs make it easy to manage user input, providing easy place holders for data, and a work flow for forms submission. Forms are separated into the view, and controller. The physical view can utilize a special Spring tag library to bind form fields to POJO properties.


Validators

These beans work with input forms to make it easy to handle business validation. They have no dependencies on Spring's Web MVCyou need only implement an interfaceso it's easy to package your validation with your business logic.

These simple enhancements let you manage the flow of control in a manner that's consistent and organized. It also lets you keep code in a consistent place, and keep coupling to a bare minimum.

2.3.1. How do I do that?

We're going to code our enhancements in two distinct steps. First, we'll configure the resolver. To do that, we're going to need to change the configuration in the rentaBikeApp-Servlet.xml by adding the following element (Example 2-13).

Example 2-13. rentaBikeApp-Servlet.xml
<bean   >    <property name="viewClass">       <value>org.springframework.web.servlet.view.JstlView</value>    </property>    <property name="suffix"><value>.jsp</value></property> </bean>

You can also add a prefix in addition to a suffixfor instance, if you store your JSPs in a subfolder or alternate path.

You'll also change the controller. This controller's purpose is to handle form submission. In the previous lab, this controller used the HttpServletRequest's parameters to access the form values, but now, it will use a POJO (Example 2-14).

Example 2-14. SubmitBikeController.java
public class SubmitBikeController extends SimpleFormController {     private RentABike facade;     public RentABike getFacade( ) { return facade; }     public void setFacade(RentABike facade) { this.facade = facade; }     public ModelAndView onSubmit(Object command)             throws ServletException{         Bike bike = (Bike)command;         facade.saveBike(bike);         return new ModelAndView(new RedirectView(getSuccessView( )),             "rentaBike", facade);     }     protected Object formBackingObject(HttpServletRequest request)            throws Exception {         Bike bike = new Bike( );         if(request.getParameter("bikeSerialNo") != null)             bike = facade.getBike(request.getParameter("bikeSerialNo"));         return bike;     } }

The controller now has an onSubmit method instead of handleRequest. onSubmit takes the POJO that holds the form field values instead of a raw HttpServletRequest. The other method, formBackingObject, allows you to initialize the POJO that will be bound to the form fields on the first request to the form.

You also need to code an input form. The form in Example 2-15 is going to make use of some new Spring-specific tags imported from the Spring taglib, which ships with the rest of the framework.

Example 2-15. editBike.jsp
<%@ page import="com.springbook.*"%> <%@ include file="include.jsp" %> <%@ taglib prefix="spring" uri="/spring" %> <html>    <head>       <title>          Edit Bike       </title>    </head>    <body>       <h1>Edit Bike</h1>       <form method="POST">          <spring:hasBindErrors name="bike">             <b>Please fix all errors!</b>          </spring:hasBindErrors>          <table border="1" cellspacing="2" cellpadding="2">             <tr>                <td align="right">Manufacturer:</td>                <td>                    <spring:bind path="bike.manufacturer">                   <input type="text" name="manufacturer" value="<c:out                       value="${status.value}"/>">                   <font color="red"><c:out                       value="${status.errorMessage}"/></font>                 </spring:bind>               </td>            </tr>            <tr>             <td align="right">Model:</td>             <td>              <spring:bind path="bike.model">               <input type="text" name="model" value="<c:out                    value="${status.value}"/>">               <font color="red"><c:out                    value="${status.errorMessage}"/></font>              </spring:bind>             </td>            </tr>            <tr>             <td align="right">Frame:</td>             <td>              <spring:bind path="bike.frame">               <input type="text" name="frame" value="<c:out                    value="${status.value}"/>">               <font color="red"><c:out                   value="${status.errorMessage}"/></font>              </spring:bind>             </td>            </tr>            <tr>             <td align="right">Serial Number:</td>             <td>              <spring:bind path="bike.serialNo">               <input type="text" name="serialNo" value="<c:out                    value="${status.value}"/>">               <font color="red"><c:out                    value="${status.errorMessage}"/></font>               </spring:bind>             </td>            </tr>            <tr>             <td align="right">Weight:</td>             <td>              <spring:bind path="bike.weight">               <input type="text" name="weight" value="<c:out                    value="${status.value}"/>">               <font color="red"><c:out                    value="${status.errorMessage}"/></font>              </spring:bind>             </td>            </tr>            <tr>             <td align="right">Status:</td>             <td>              <spring:bind path="bike.status">               <input type="text" name="status" value="<c:out                    value="${status.value}"/>">               <font color="red"><c:out                    value="${status.errorMessage}"/></font>              </spring:bind>             </td>            </tr>           </table>           <input type="submit" value="Submit">         </form>     </body> </html>

See how you surround the form input fields with the <spring:bind> tags. This allows Spring to automap the values of the input fields to our POJO command object, and later, allows it to show error messages if the validation fails. At the top of the page, you can use the <spring:hasBindErrors> tag (passing in our command object) to display an error summary if there are validation errors.

You'll want Spring to validate the form, so add a specific validator (Example 2-16). You can package it with a business object. The controller will apply the correct work flow, including calling the validation.

Example 2-16. BikeValidator.java
public class BikeValidator implements Validator {     public boolean supports(Class aClass) {         return aClass.equals(Bike.class);     }     public void validate(Object o, Errors errors) {         Bike bike = (Bike)o;         if(bike == null) {             errors.rejectValue("manufacturer", "Error!",                    null, "Value required.");         } else {             if(bike.getManufacturer( ) == null ||                    "".equals(bike.getManufacturer( )))                                    errors.rejectValue("manufacturer", "Value not present.",                           null, "Manufacturer required.");                         if(bike.getModel( ) == null || "".equals(bike.getModel( )))                 errors.rejectValue("model", "Value not present.", null,                     "Model is required.");         }     } }

Next, modify the context as in (Example 2-17); also, in the urlMapping, point /editBike.bikes to editBikeForm instead of editBikeController.

Example 2-17. rentaBikeApp-Servlet.xml, editBike.bikes should point to editBikeForm
    <bean  />     <bean  >         <property name="sessionForm"><value>true</value></property>         <property name="commandName"><value>bike</value></property>         <property name="commandClass">            <value>com.springbook.Bike</value>          </property>         <property name="validator"><ref bean="bikeValidator"/></property>         <property name="formView"><value>editBike</value></property>         <property name="successView"><value>bikes.bikes</value></property>         <property name="facade">             <ref bean="rentaBike"/>         </property>     </bean>

Next, you'll need to add the CRUD functionality to ArrayListRentABike that you specified earlier in the RentABike interface.

Example 2-18. ArrayListRentABike.java
package com.springbook; import java.util.*; public class ArrayListRentABike implements RentABike {     private String storeName;     final List bikes = new ArrayList( );     public void setStoreName(String name) {         this.storeName = name;     }     public String getStoreName( ) {         return storeName;     }     private void initBikes( ) {         bikes.add(new Bike("Shimano", "Roadmaster", 20, "11111", 15, "Fair"));         bikes.add(new Bike("Cannondale", "F2000 XTR", 18, "22222", 12,             "Excellent"));         bikes.add(new Bike("Trek", "6000", 19, "33333", 12.4, "Fair"));     }     public ArrayListRentABike( ) {         initBikes( );     }     public ArrayListRentABike(String storeName) {         this.storeName = storeName;         initBikes( );     }     public String toString( ) { return "com.springbook.RentABike: " + storeName; }     public List getBikes( ) { return bikes; }     public Bike getBike(String serialNo) {         Iterator iter = bikes.iterator( );         while(iter.hasNext( )) {             Bike bike = (Bike)iter.next( );             if(serialNo.equals(bike.getSerialNo( ))) return bike;         }         return null;     }     public void saveBike(Bike bike) {         deleteIfContains(bike);         bikes.add(bike);     }     public void deleteBike(Bike bike) {         deleteIfContains(bike);     }     private void deleteIfContains(Bike bike) {         Iterator iter = bikes.iterator( );         while(iter.hasNext( )) {             Bike comp = (Bike)iter.next( );             if(comp.getManufacturer( ).equals(bike.getManufacturer( )) &&                 comp.getModel( ).equals(bike.getModel( ))) {                 bikes.remove(comp);                 return;             }         }     } }

Finally, you'll need to add the Spring taglib to the web.xml file so that your new JSP tags will work.

Example 2-19. web.xml
<taglib>     <taglib-uri>/spring</taglib-uri>     <taglib-location>/WEB-INF/lib/spring.tld</taglib-location> </taglib>

Go ahead and build and deploy the changed application. Figure 2-3 shows a view of what happens when you don't enter the Manufacturer or Model for a bike.

Figure 2-3. Manufacturer and Model missing


2.3.2. What just happened?

Within the Spring configuration file, you specified the details for a view resolver. This component decouples the view from the technology that you use to render it. In this case, the resolver lets you refer to a JSP by name, instead of through a filename.

In the previous simpler example, the control was straightforward. An HTTP request triggered a controller, which then loaded another form. This application is slightly more advanced, because Spring's forms let you provide a more sophisticated workflow, and one that's more appropriate for basic input form submission and validation. In this case, you set up and configured an input form, with custom JSP tags, and then submitted it. The Post will trigger the dispatcher, as before, and then fire the command, invoke the validator, and then return the form view if errors existed, or the success view if there were no errors. If you're familiar with the Jakarta Struts project, this flow will be familiar to you.

    team bbl



    Spring. A developer's Notebook
    Spring: A Developers Notebook
    ISBN: 0596009100
    EAN: 2147483647
    Year: 2005
    Pages: 90

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