ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Persistence in Spring
Pages: 1, 2, 3

Presentation

In most places, the Spring framework doesn't reinvent working technologies. In the area of presentation logic, though, Spring introduces a simple model-view-controller framework called MVC Web that has many competing architectures, like Struts and Java Server Faces (JSF). Take solace, though. You don't have to use MVC Web to use Spring. But if you decide to do so, you will find a few advantages:



  • MVC Web does not dictate your choice of view. Other frameworks tend to provide better support for favored view technologies, such as Velocity (proprietary) and Struts (JSP). For example, Struts exposes the model via request attributes. As a result, you need to build a bridge servlet to use a technology such as Velocity that doesn't understand the Servlet API. Spring exposes the model through a generic map, so it can work with any view technology.

  • MVC Web provides consistent configuration across all aspects of a Spring application. It uses the same inversion-of-control paradigm that the other frameworks use.

  • MVC Web makes testing easier. Since you don't have to extend another class (like Action or ActionForm in Struts), you can easily mock the request and response.

If you've ever used Struts, you're familiar with the basic paradigm of MVC Web. Figure 8-4 shows how it works. Controllers basically handle all incoming requests from input views. If the input request is a submitted form, the controller calls a business validation routine, created and configured by the programmer, and sends either the associated error view or success view back to the user, based on results.

Figure 8-4
Figure 8-4. The MVC Web framework works much like Struts

Configuration

As with other elements of the Spring framework, when you're trying to understand a new application, start with the configuration files and drill down from there. In this example, the user interface is configured in the petstore-servlet.xml file.

Consider HTML pages that search for products in a category, and search for products based on keywords. The configuration file needs two controllers to the application context file. Each entry specifies a controller and the model object, like in Example 8-10.

Example 8-10. Excerpt from web.xml

  <bean name="/shop/searchProducts.do" 
     class="jpetstore.web.spring.SearchProductsController">
     <property name="petStore"><ref bean="petStore"/></property>
  </bean>

  <bean name="/shop/viewProduct.do" class="org.springframework.samples.jpetstore.web.
spring.ViewProductController">
     <property name="petStore"><ref bean="petStore"/></property>
  </bean>

Recall that all access to our data layer goes through the façade. As you'd expect, these bean ID entries specify the façade, called petstore. Each form in the application works in the same way. Let's drill down further and look at the controller for searchProducts.

Controllers

For MVC Web, each form generally shares a single instance of a controller, which routes all requests related to a given form. It also marshals the form to the correct validation logic and returns the appropriate view to the user. Example 8-11 shows the controller for the searchProducts view.

Example 8-11. SearchProductsController.java

   public class SearchProductsController implements Controller {

[1] private PetStoreFacade petStore;

    public void setPetStore(PetStoreFacade petStore) {
       this.petStore = petStore;
    }

[2] public ModelAndView handleRequest(HttpServletRequest request,
                                      HttpServletResponse response) 
      throws Exception {

[3]    if (request.getParameter("search") != null) {
          String keyword = request.getParameter("keyword");
          if (keyword == null || keyword.length( ) == 0) {
             return new ModelAndView("Error", 
                                 "message", 
      "Please enter a keyword to search for, then press the search button.");
          }
          else {
[4]          PagedListHolder productList = new PagedListHolder(
                     this.petStore.searchProductList(keyword.toLowerCase( )));
             productList.setPageSize(4);
             request.getSession( ).setAttribute(
                     "SearchProductsController_productList", productList);
[5]          return new ModelAndView("SearchProducts", "productList", productList);
          }
       }
       else {
[6]       String page = request.getParameter("page");  
          PagedListHolder productList = (PagedListHolder) request.getSession( ).
              getAttribute("SearchProductsController_productList");
          if ("next".equals(page)) {
             productList.nextPage( );
          }
          else if ("previous".equals(page)) {
             productList.previousPage( );
          }
          return new ModelAndView("SearchProducts", "productList", productList);
       }
      }
	  
   }

Here's what the annotations mean:

[1] Each controller has access to the appropriate domain model. In this case, it's natural for the view to access the model through our façade.

[2] A controller has an interface like a servlet, but isn't actually a servlet. User requests instead come in through a single dispatcher servlet, which routes them to the appropriate controller, populating the request membermeter. The controller merely responds to the appropriate request, invoking business data and routing control to the appropriate page.

[3] In this case, the request is to "search." The controller must parse out the appropriate keywords.

[4] The controller invokes the business logic with the keywords provided by the user.

[5] The controller routes the appropriate view back to the user (with the appropriate model).

[6] In this case, the request is "page." Our user interface supports more products than might fit on a single page.

Forms

Just like Struts, Spring can map HTML forms onto Java objects. Example 8-12 is the Java bean that's returned when a Pet Store user registers an account.

Example 8-12. AccountForm.java

public class AccountForm {

  private Account account;

  private boolean newAccount;

  private String repeatedPassword;

  public AccountForm(Account account) {
    this.account = account;
    this.newAccount = false;
  }

  public AccountForm( ) {
    this.account = new Account( );
    this.newAccount = true;
  }

  public Account getAccount( ) {
    return account;
  }

  public boolean isNewAccount( ) {
    return newAccount;
  }

  public void setRepeatedPassword(String repeatedPassword) {
    this.repeatedPassword = repeatedPassword;
  }

  public String getRepeatedPassword( ) {
    return repeatedPassword;
  }

}

Each of these bean fields corresponds directly to an HTML input field or control. The Spring framework translates a submit request to the form, which can then be accessed as a POJO for validation, mapping input data, or other purposes. With Spring, unlike Struts, form objects can be any Java bean. There's no need to extend ActionForm. That's important, because you don't need to copy properties from an ActionForm to a domain object or value object.

Validation

You may have noticed validation logic within the original applciationContext.xml. These beans are generally considered business logic, but they've got a tight relationship to the user interface and they're invoked directly by the Spring framework. When a user submits a form, Spring fires the validation logic. Based on the result, Spring routes control to the appropriate page. Example 8-13 shows the AccountValidator class, which validates the account form.

Example 8-13. AccountValidator.java

public class AccountValidator implements Validator {
   public boolean supports(Class clazz) {
      return Account.class.isAssignableFrom(clazz);
   }

   public void validate(Object obj, Errors errors) {
      ValidationUtils.rejectIfEmpty(errors, "firstName", "FIRST_NAME_REQUIRED", 
      ValidationUtils.rejectIfEmpty(errors, "lastName", "LAST_NAME_REQUIRED", 
      ValidationUtils.rejectIfEmpty(errors, "email", "EMAIL_REQUIRED", 
      ValidationUtils.rejectIfEmpty(errors, "phone", "PHONE_REQUIRED", 
      ValidationUtils.rejectIfEmpty(errors, "address1", "ADDRESS_REQUIRED", 
      ValidationUtils.rejectIfEmpty(errors, "city", "CITY_REQUIRED", 
      ValidationUtils.rejectIfEmpty(errors, "state", "STATE_REQUIRED", 
      ValidationUtils.rejectIfEmpty(errors, "zip", "ZIP_REQUIRED", "ZIP is required.");
      ValidationUtils.rejectIfEmpty(errors, "country", "COUNTRY_REQUIRED", 
   }
}

In this example, the Spring framework makes life easier for developers in several ways. The developer does not need to write validation methods by hand. Also, many prepackaged methods exist. The framework takes care of validation and routing. The framework takes care of routing control based on success or failure.

One chapter on the Spring framework cannot do it justice, but you've seen the overall gist of it. The advantages of the framework—and more importantly, this coding style—should jump off the page at you if you haven't seen it before. In particular, notice the clarity and simplicity that a cleanly layered architecture provides. You can probably imagine how easy it is to incorporate business logic with a transparent framework like Spring.

Summary

I've chosen the jPetStore application for a variety of reasons. The biggest is that you can quickly see the difference between a simple, fast, light application and the alternative. If you are not yet a believer, I challenge you to look up the EJB version of Pet Store. If you've never seen it, you'll be blown away by the difference. Our version is transparent and independent; the EJB example is invasive and dependent on the container. Ours is easy to understand, whereas the J2EE counterpart was buried under the complexity of EJB best practices.

I haven't always been a believer. In fact, I didn't know who Rod Johnson was before we were introduced in Boston at a conference. I've since come to appreciate this simple framework as elegant and important. If you're new to Spring, you've seen only a single application. I hope that through it, you can see how it embraces the principles in this book:

Keep it simple

Spring's easy to use and understand. In a single chapter, our example covers an application with transactions, persistence, a full web frontend, and a completely modular configuration engine.

Do one thing, and do it well

Spring's framework has many different aspects and subframeworks. However, it separates each concept nicely. The fundamental value of Spring is the bean factory and configuration service, which let you manage dependencies without coupling your code. Each additional layer of Spring is cleanly decoupled and independent.

Strive for transparency

Spring applications don't need to rely on the basic container at all. In fact, they can easily exist outside of the container. You need only create and configure them manually. This ability makes Spring applications a joy to test.

You are what you eat

Spring makes smart choices in the frameworks that it includes. The respected Apache projects for data sources and logging form a good foundation. Spring allows many configurable choices, letting you choose the best frameworks for a given solution.

Allow for extension

Spring may be the most open, extensible container in existence today. It allows effective and rapid extension with common configuration services and clean abstractions.

I haven't covered Spring in its entirety. My goal is only to show you that it's possible to build real-world applications that embrace the concepts set out in the first six chapters of this book. If you decide that you'd like to see more, make sure that you look into Spring's advanced features:

  • Integration with Hibernate and JDO
  • AOP concepts
  • Transactional templates with JTA support

The authors of Better, Faster, Lighter Java continue to explore practical examples of the principles of their book in other chapters. Pick up your copy to see, for example, an implementation of a service called Simple Spider, and see that service integrated into Spring. Then, you'll be able to see the benefits of improved maintenance of a framework like this going forward.

Justin Gehtland is a programmer, author, mentor and instructor, focusing on real-world software applications.


Return to ONJava.com.