Chapter 4. Basic web forms
This chapter covers
- Building a web form
- Externalizing strings in a view
- Validating and saving form data
Web forms provide a means by which we can collect data from end users. As such, they’re a key aspect of any nontrivial web application. This chapter shows how to use Spring Web MVC and related technologies to build a simple user registration form with standard features such as redirect-after-post, externalized strings, form data validation, and persistence.
Our approach is hands-on and practical. See Spring in Action, 3rd edition by Craig Walls (Manning, 2011) for additional material on Spring Web MVC.
None
Spring Web MVC, Spring form tag library
Users establish a relationship with a website or an organization by registering. The resulting user account allows logins, order placement, community participation, and so on. The first step in supporting a user registration process is to display a registration form.
Create a web-based form.
In this recipe you’ll use Spring Web MVC to display a user registration form. You’ll build a user account form bean, a web controller, a registration form, and a confirmation page.
It won’t hurt to have a visual on the UI you’re planning to create in this recipe. Figure 4.1 shows what you’re aiming for.
Let’s begin by creating a form bean for your user accounts.
You use a form bean to store form data, as shown in the following listing.
AccountForm is a POJO.[1] It has properties for personal , marketing
, and legal
data. These are typical concerns when modeling user accounts. You also include a descriptive toString() method
, based on the Commons Lang library, so you can observe the form-binding later in the recipe. By design, you suppress the password here to avoid accidentally revealing it.
You default the marketingOk property to true because you’d like to market to your users unless they explicitly opt out. On the other hand, you default acceptTerms to false because you want the user’s acceptance of the terms of use to be active rather than passive. Presumably this gives you a stronger legal leg to stand on in the event of a disagreement with the user.[2]
2 Disclaimer: We aren’t lawyers! Consult a qualified legal expert if necessary.
You have a form bean, but without a web controller, it’s inert. Let’s take care of that.
Your account controller, which appears in the following listing, handles form delivery and processing.
At the @Controller annotation tells Spring that this is a web controller. You establish a base path for request mapping using the @RequestMapping annotation
. This path contextualizes paths declared at the method level. At
you’re not implementing any special interfaces or extending special classes.
You serve the empty form bean at . The associated request mapping is /users/new, which you obtain by combining the class-level /users base path with the method-level new mapping. (To override a class-level mapping rather than refine it, place a slash in front of the method-level mapping.) The method itself places a new AccountForm instance on the model under the key account and returns the view name.
You process form submissions at , specifying the POST request method. The request mapping is just /users because that’s the result of combining the base path with the empty string. For now, when users post form data, you log it and redirect them to a view that thanks them for registering
. We’ll discuss the redirection in more detail later in the recipe.
Let’s move on to the two view pages. First you’ll create the view for the registration form, and after that you’ll create the “thanks” page for successful form submissions.
The next listing shows how to implement the registration form from figure 4.1. Note that we’ve suppressed the layout and CSS code; see the code download (src/main/webapp/WEB-INF/jsp/users/registrationForm.jsp) for the full version.
The registration page uses the form tag to create an HTML form. You use action="." to post the form submission to /main/users/. The modelAttribute attribute references the model object to be used as the form-backing bean. The HTML form elements are bound to the form bean’s properties in both directions:
- Inbound— The form bean is populated with the HTML form element values when the form is submitted and passed to the controller for validation and processing.
- Outbound— The form elements are prepopulated with the form bean’s values. You use this, for example, to set the default value of the marketingOk check box to true and acceptTerms to false. Form elements are also prepopulated before representing a form to a user for remediating invalid form data; you’ll see this in recipe 4.3.
Figure 4.2 presents a high-level view of form binding.
Figure 4.2. Formbinding in action. Stars show where form fields and bean properties are bound together.

You use input , password
, and checkbox
tags from the Spring form tag library to render HTML form elements. These are essentially form-binding versions of the corresponding HTML elements. The tag library doesn’t provide anything for submit buttons (there’s nothing to bind to here), so you use standard HTML
.
After the user successfully submits a registration, you need a page to let the user know that the registration succeeded. Here’s a minimalistic registrationOk.jsp file:
In this case, the page doesn’t even need to be a JSP, although you’ll leave it as is because it’s always possible that you’ll want to present dynamic information through the page.
You’re done with your form bean, controller, and views. All that remains is configuration.
The key part of your web.xml configuration is the following:
This web.xml configuration references a single Spring configuration, called beans-web.xml, associated with the DispatcherServlet. It goes in src/main/resources/spring so it will be on the classpath when you package and deploy the app.
The listing ties everything together. You use component scanning to discover the AccountController based on its @Controller annotation.
Spring 3 introduces the mvc namespace. You use <mvc:annotation-driven> at to activate annotation-based configuration inside the DispatcherServlet explicitly.
At you use <mvc:view-controller> to configure a new controller for the registration success page. Recall from listing 4.2 that you redirected the request to a success page, but you never specified a controller to display the success page. That’s what <mvc:view-controller> does. It creates a ParameterizableViewController instance whose job is to accept requests for /users/registration_ok and serve up the logical view name users/registrationOk for view resolution.
You redirect rather than forward to the success page because you want to apply the redirect-after-post pattern to your form submission. With this pattern, a successful form submission issues an HTTP redirect to avoid resubmissions if the user reloads or bookmarks the page, as illustrated by the sequence diagram in figure 4.3.
The figure suppresses the ViewResolver, but the DispatcherServlet uses the instance you created for both view resolutions depicted. The DispatcherServlet uses the ViewResolver to convert logical view names into views.
Why do you need <mvc:annotation-driven>?
You might wonder why you need to declare <mvc:annotation-driven> explicitly. After all, the DispatcherServlet default configuration already has an internal DefaultAnnotationHandlerMapping instance to handle @RequestMapping annotations. The reason: behind the scenes, <mvc:view-controller> creates a SimpleUrlHandlerMapping to map the ParameterizableViewController to the specified path, and this replaces the DefaultAnnotationHandlerMapping that would otherwise have been created. You use <mvc:annotation-driven> to indicate that you want the DefaultAnnotationHandlerMapping as well.
That almost wraps it up for the configuration. You’ll also need a WEB-INF/decorators.xml file for SiteMesh; see the code download for that. To run the app, run Maven with the jetty:run goal. On the command line, it looks like this:
Then go to http://localhost:8080/sip/users/new.html. You should see a registration page that looks like the one from figure 4.1.
What you’ve done so far isn’t tied to registration forms; this recipe is a blueprint for displaying web forms in general. As you move forward in the chapter, you’ll continue to target registration forms, but the discussion and techniques are broadly applicable.
In the next recipe, you’ll make your view pages more flexible by externalizing the strings that appear in the JSPs.
Recipe 4.1 Displaying a web form
Java resource bundles, Spring tag library
It’s often desirable to decouple a view from the specific bits of text rendered in the view. Reasons include internationalization and centralized management. This recipe shows how.
Externalize the strings that appear in the registration JSPs so they can be managed centrally.
The solution involves three steps:
1. Create a resource bundle that contains the externalized strings, or messages in the Spring vernacular.
2. Add a ReloadableResourceBundleMessageSource to the configuration.
3. Replace the hardcoded strings in the JSPs with references to the externalized strings in the resource bundle.
First up is the resource bundle, which contains your messages.
The following listing shows how to create a resource bundle for your messages. This file goes in src/main/resources because you want it to appear at the root of the classpath on deployment.
You can organize these messages as you like. In this case, you have three sections: one for messages that are common to both pages , another for registration form messages
, and a third for messages that appear on the success page
. The key names reflect this organization.
Next you add a single bean to the beans-web.xml configuration.
Add the following code snippet to beans-web.xml:
This creates a message source, backed by the resource bundle, that you can use to drive dereferencing in the JSP. The ID messageSource is required.
The third and final step is to replace the hardcoded strings in the JSP with references.
The next listing shows how to convert hardcoded strings into references using the <spring:message> tag.
We’ve suppressed a good chunk of the code in listing 4.6, but it should be obvious given what we’ve included how to convert the rest of listing 4.3. First you declare the spring tag library .[3] Then you use the <spring:message> tag to set a couple of variables to messages in the resource bundle
so you can use them later. You use the pageTitle variable at
and also inside the following <h1>, and you use the msgAllFieldsRequired variable at
. At
you use <spring:message> in a slightly different fashion; this time, you dump the message right into the template. This occurs because you haven’t specified a var attribute.
3 The spring and form tag libraries come from the org.springframework.web.servlet artifact, and the corresponding tag library descriptors are spring.tld and spring-form.tld, respectively. You can find these inside the JAR’s META-INF directory.
That’s it for the changes. Run the app the same way you ran it in recipe 4.1. Under the hood, you’ve externalized the strings, but you shouldn’t see any behavioral changes.
It’s a good practice to externalize application strings. Besides paving the way for internationalization, it gives you a central place to manage text. This helps with quality control, and it helps when you decide you want to change, for example, “Technical Support Representative” to “Customer Care Specialist” across the board.
So far your form is very permissive. You can enter whatever you like into the form—including nothing—and the result is always success. In the following recipe, you’ll fix that with form validation.
Recipe 4.2 Externalizing strings in the view
Spring Web MVC, Spring binding and validation APIs, JSR 303 Bean Validation, JSR 223 Java Scripting, Hibernate Validator, Spring form tag library
No matter how intuitive your registration form, people will accidentally or even intentionally fill it out with invalid information. You treat such errors as user errors rather than system or application exceptions, meaning you usually want to explain the error to the user in nontechnical language and help them overcome it.
When users submit form data, validate it before performing further processing. If there are errors, help the user understand what went wrong and how to address the issue.
At the highest level, this recipe addresses two types of validation:
- Field filtering— Ensure that all submitted field names are permissible. In general, clients shouldn’t be allowed to submit fields that don’t appear on the form.
- Field validation— Ensure that all submitted field values follow validation rules.
We’ll set the stage with an architectural overview. Spring Web MVC supports both types of validation just described using three key APIs: Spring’s form-binding API, Spring’s validation API, and JSR 303 Bean Validation. See figure 4.4.
Figure 4.4. Validation in Spring Web MVC. The form-binding API handles field filtering, JSR 303 handles bean validation, and there’s a Spring validation API for custom logic.

Here’s how it works. When users submit HTML form data, Spring Web MVC uses the form-binding API to bind the HTTP parameters to form bean properties in an automated fashion. In certain cases—for example, when a form bean is performing double duty as a persistent entity—the form bean may have properties that aren’t intended binding targets. The form-binding API allows you to filter out unwanted HTTP parameters by silently ignoring them during binding.
When Spring Web MVC invokes a form-submission request-handler method, such as postRegistrationForm(), it passes in the form data. In general, the form data is encapsulated within a form bean, and you want to validate it. This is the domain of JSR 303 Bean Validation. Spring Web MVC uses JSR 303 to validate form data encapsulated in this fashion, and developers use the Spring validation API (specifically, the BindingResult interface) from within a controller to determine whether the bean is valid.
Sometimes you need to perform a bit of custom validation logic. You’ll see an example. Spring’s validation API provides a programmatic interface for implementing such logic.
That will do for an overview. Let’s add field filtering to the AccountController.
Recall that Spring Web MVC automatically binds HTML forms to an underlying form bean. Although this is a major convenience to application developers, it raises a security concern because it allows attackers to inject data into form bean properties that aren’t intended to be accessed via the HTML form. You’re not in that situation here, but it’s a common state of affairs in cases where a single model object performs double duty as both a form bean and a persistent entity. In such cases you need a way to guard against data injection.[4]
4 Consider the case where you use a single Account POJO to serve as both an entity and a form bean. The entity might have an enabled field that indicates whether the account is enabled. You wouldn’t want clients to be able to manipulate that field by sending a value for the field to the form processor.
Spring Web MVC supports this using @InitBinder methods. Add the following method to AccountController:
The @InitBinder annotation tells Spring Web MVC to call this method when initializing the WebDataBinder responsible for binding HTTP parameters to form beans. The setAllowedFields() method defines a whitelist of bindable form bean fields. The binder silently ignores unlisted fields.
Whitelisting vs. blacklisting
The list of allowed fields is an example of a whitelist. The idea is that nothing gets through unless it’s on the whitelist.
There is an alternative approach called a blacklist. With a blacklist, everything gets through unless it’s on the blacklist.
Whitelists are generally more secure, because they start with an assumption of distrust rather than trust. But blacklists have their place as well. For example, you might filter out comment spammers using an IP blacklist, because it wouldn’t be practical to use a whitelist for web traffic.
Now let’s examine field validation.
Several steps are involved in adding form validation to your app:
1. Add a JSR 303 implementation to the classpath.
2. Add validation annotations to AccountForm.
3. Add @ModelAttribute, @Valid, BindingResult, and validation logic to AccountController.
4. Create a ValidationMessages.properties resource bundle, and update the messages.properties resource bundle.
6. Confirm that beans-web.xml has <mvc:annotation-driven> (for validation) and a message source (for certain custom error messages).
There’s a lot to cover. Let’s start at the top of the list and work our way down.
Your Maven build takes care of placing Hibernate Validator 4, a JSR 303 implementation, on the classpath. Spring Web MVC will automatically pick it up. You can therefore move on to the next step, which is marking up AccountForm with validation annotations.
The following listing updates the AccountForm from listing 4.1 by adding validation annotations.
Listing 4.7. AccountForm.java, with validation annotations (updates listing 4.1)


The previous listing uses the Bean Validation (JSR 303) standard and Hibernate Validator to specify validation constraints. You attach the annotations either to the fields or to the getters. At you indicate that the username property can’t be null, and its size must be 1–50 characters in length. At
you use the Hibernate-specific @Email annotation to ensure that the email property represents a valid e-mail address. At
you require that the acceptTerms property be true for validation to succeed, and you specify a message code to use when the validation fails. (More on that shortly.)
Finally, you declare a class-level @ScriptAssert annotation at . This Hibernate annotation, which was introduced with Hibernate Validator 4.1, allows you to use a script to express validation constraints involving multiple fields. Here you use JavaScript to assert that the password and confirmation must be equal. (The Rhino JavaScript engine is automatically available if you’re using Java 6; otherwise you’ll need to place a JSR 223–compliant [Scripting for the Java Platform] script engine JAR on the classpath.) In addition to JavaScript, there are many other language options, including Groovy, Ruby, Python, FreeMarker, and Velocity.
Next you update AccountController to validate the account bean.
The next listing shows how to update the AccountController from listing 4.2 to support both Bean Validation via JSR 303 and custom password validation.
Listing 4.8. AccountController.java, updated to validate form data (updates listing 4.2)


You add @ModelAttribute and @Valid annotations to the AccountForm parameter . The @ModelAttribute annotation causes the account bean to be placed automatically on the Model object for display by the view, using the key "account". The @Valid annotation causes the bean to be validated on its way into the method.
Spring exposes the validation result via the BindingResult object . This is how you can tell whether bean validation turned up any errors. You can also programmatically add new errors to the BindingResult by using its various reject() and rejectValue() methods. The BindingResult method parameter must immediately follow the form bean in the method parameter list.
The logic of the postRegistrationForm() method itself is straightforward. You call convertPasswordError() , which converts the global error that @ScriptAssert generates into an error on the password field. You use the rejectValue() method to do this, as mentioned, passing in an error code "error.mismatch". This error code resolves to one of the following message codes, depending on which message codes appear in the resource bundle:
- error.mismatch.account.password (error code + . + object name + . + field name)
- error.mismatch.password (error code + . + field name)
- error.mismatch.java.lang.String (error code + . + field type)
- error.mismatch (error code)
These message codes are listed in priority order: if the resource bundle contains the first message code, then that’s the resolution, and so forth.[5] The first message code does in fact appear in messages.properties. See the Javadoc for Spring’s DefaultMessageCodesResolver for more information on the rules for converting error codes to message codes.
5 It’s probably worth emphasizing the fact that despite superficial similarities, error codes and message codes aren’t the same thing. Validation errors have associated codes, and these generally map to a set of resource bundle message codes, which in turn map to error messages. It’s pretty easy to get these mixed up.
Finally, once you’ve processed any password errors, you check to see whether there were any validation errors, and route to a success or failure page accordingly . Notice that you’re using the view name constants defined at the top of the file.
Let’s take a more detailed look at the error messages here.
First let’s talk about the default JSR 303 and Hibernate Validator messages. Strictly speaking, you don’t have to override them at all. But the defaults aren’t particularly user-centric (one of the defaults, for example, references regular expressions), so you’ll change the messages for the constraints you’re using. JSR 303 supports this by allowing you to place a ValidationMessages.properties resource bundle at the top of the classpath. You’ll use this resource bundle not only to override the JSR 303 and Hibernate Validator defaults, but also to define an error message specific to the acceptTerms property.
You override the default JSR 303 @Size and default Hibernate Validator @Email
error messages as shown. The message for @Size is effectively a template that generates messages with the minimum and maximum sizes substituted in. You aren’t overriding the default JSR 303 error message for @NotNull because that error shouldn’t occur if you don’t forget to implement any form fields. (And if you do, the default error message is OK because this is a programming error rather than an end user error.) Finally, you define an error message for the acceptTerms property at
.
In addition to the JSR 303 error messages, you need messages for the Spring-managed errors. You’ll add these to messages.properties because ValidationMessages.properties is for JSR 303 error messages. Although it can be a little confusing to split the error messages into two resource bundles, it helps to do exactly this. The reason is that JSR 303 and Spring use different schemes for resolving error codes to message codes, and mixing error messages in a single resource bundle can make it harder to keep message codes straight.
Add the following two error messages to messages.properties:
Now you have an error message for the password-mismatch error code you used in the controller. You’ll use the global error message in the form JSP.
You use the Spring form tag library to display both a global error message (“Please fix the problems below”) and error messages on the form bean, as illustrated in figure 4.5.
Figure 4.5. The revised registration form, with a global error message and field-level error messages

The text fields for properties with errors are visually distinct (they have red borders), although it’s hard to tell if you’re viewing the figure in black and white. Also, fields are prepopulated with the user’s submitted data so the user can fix mistakes instead of reentering all the data. The only exceptions are the two password fields, which for security reasons you don’t prepopulate. The user has to reenter those values.
To accomplish this design, you’ll need to revise registrationForm.jsp as shown next. (See the code download for the full version.)

At you display the global error message. The tag logic here is to look for the existence of any error whatsoever—a global error or a field error—and if there is one, display the global error message. The path="*" piece is your error wildcard.
You display the username field at . By using the <form:input> tag, you get data prepopulation for free. This time around you include the CSS attributes because there’s something interesting to show off. The cssClass attribute specifies the <input> element’s CSS class when there’s no error. (The short class just sets the text-field width in the sample code.) The cssErrorClass attribute specifies the class when there is an error. This allows you to change the visual appearance of the text field when there’s an error.
In addition to the text field, you want to display the error message, and that’s what’s going on at . You select the specific form bean property with the path attribute and use htmlEscape="false" so you can include HTML in the error message if desired.
The other fields are essentially the same, so we’ve suppressed them. Again, please see the code download for the full version of the code.
The last step in the process is to configure the application for validation.
Surprise—you’ve already done what you need to do here. In recipe 4.1 you included the <mvc:annotation-driven> configuration inside beans-web.xml, which among several other things activates JSR 303 Bean Validation, causing Spring Web MVC to recognize the @Valid annotation. In recipe 4.2 you added a MessageSource.
Start up your browser and give the code a spin.
The preceding recipe handles validation in the web tier. There’s nothing wrong with that, because the constraints you’ve used so far make sense as web tier constraints. But it’s important to bear in mind that modern validation frameworks like Spring validation and JSR 303 validation abandon the traditional assumption that bean validation occurs exclusively in the web tier. In the following recipe, you’ll see what validation looks like in the service tier.
Recipe 4.1 Displaying a web form
Recipe 4.3 Validating form data
Spring, JPA, Hibernate 3, Spring JdbcTemplate, MySQL, or other RDBMS
So far you’re accepting and validating user registrations, but you aren’t saving the data to a persistent store. In this recipe, you’ll persist data using Spring, JPA, Hibernate, and JDBC. You’ll also perform service-tier validation to avoid duplicate usernames.
Save form data to a persistent store.
Although you’ll save your form data to a database, you’re not going to save the AccountForm form bean directly. The main reason is that there’s a mismatch between the form bean and what you’d want out of a domain object:
- For security purposes, you don’t want your domain object to have a password property. (You don’t want a bunch of in-memory passwords sitting around.)
- Your domain object will have an enabled field that the form bean doesn’t have.
Instead, you’ll create a separate Account domain object and then have the controller translate the AccountForm into an Account before saving the Account.
Why not save the form bean directly?
It’s possible to have a single POJO serve as both a form bean and a domain object, but architecturally it’s cleaner to separate the two, especially if there are material differences between them. Here the security difference seems important enough to warrant two separate classes.
Note that if you were to use a single POJO, then the @InitBinder method from recipe 4.3 would allow you to prevent users from setting the enabled property.
Having said all that, the choice is partly a matter of style. Especially with traditional designs based on anemic domain objects, it’s common to see a single POJO supporting presentational, domain, and persistence concerns. This might change, though, if domain-driven design (DDD) catches on in the Spring community. (Spring Roo promotes a DDD approach.) As domain objects get richer, they become less suitable as form beans.
You’ll use a combination of Hibernate, JPA annotations, and JDBC to persist the user registration data. Hibernate will work nicely for saving the Account domain object, but you need a way to save user passwords as well, and Hibernate won’t help there because the password isn’t part of Account. So, you’ll use straight JDBC to save the password. The POJO and password data need to be saved as part of the same transaction, and we’ll also show how to do that.
This recipe adds a lot of infrastructure to what you already have. See figure 4.6.
Figure 4.6. Bean-dependency diagram for saving user registration data. We’re including infrastructure for both Hibernate- and JDBC-based persistence.

You’ll start with the database schema, then build out the code and configuration on top of that.
The following listing presents the database schema for MySQL, which involves a single table for storing user accounts.
Notice that you coordinate the database constraints in listing 4.11 with the validation constraints in recipe 4.3. For example, the field-size maximums are generally 50 in both locations. (The exception is that the password column in the database allows 64 characters to accommodate SHA-256 hashes, as you’ll see in recipe 6.7.) Also, you include a password column here even though the Account domain object won’t have a corresponding property.
Speaking of Account, let’s create it, because you’ll need it for what follows.
The next listing presents the Account domain object, with JPA annotations for persistence.

You use the JPA @Entity annotation to mark your domain object as a persistent entity, and @Table
to associate the entity with a database table. At
you use @Id, @GeneratedValue, and @Column on the getId() method to establish it as an ID property mapped to a database column called id, with GenerationType.AUTO indicating that the JPA provider (Hibernate in this case) is responsible for determining the right ID-generation strategy for the underlying database. (IDs might be generated by an autoincrement column, or perhaps by a sequence, and so on.)
For most properties, the column mapping is a matter of attaching an @Column annotation to the getter method or the field. You can see this with getUsername() .
In the case of the fullName property, it’s a convenience method rather than a persistent field, so you mark it with @Transient to prevent Hibernate from trying to persist it. You can also use JPA to define named queries supporting finder methods. At
you define a named query to look up accounts by username. You’ll use this query in your data access object.
You need both an interface and an implementation for your DAO. The interface extends the Dao interface from chapter 1 by adding a password-aware create() method (recall that the Account doesn’t have a password property) and a finder-by-username:
The DAO implementation in the following listing is more interesting. You derive it from AbstractHbnDao in chapter 1, but note that it isn’t a pure Hibernate DAO.
You use @Repository to tag HbnAccountDao as a DAO. This allows Spring to discover the bean during component scanning.
Now we get to the interesting part. You’re doing both Hibernate and JDBC inside this DAO. Hibernate handles everything on the Account POJO, but the password is a standalone field. So you need JDBC to update that. First you define a password-update statement at . You also inject a JdbcTemplate at
to execute the update. At
you have Hibernate and JDBC working together to save the user account data, including the password. A Hibernate Session sits behind the call to create(). Then you run the JDBC password update using the JdbcTemplate.
Besides saving account information, you have a finder for looking up an account by username . You’ll use this to check for duplicate usernames when the user tries to register an account. The finder uses the JPA named query you created on the Account domain object in listing 4.12.
Now let’s create an account service around the account DAO.
You’ll create a service with a single method for registering valid users. Here is the service interface:
Notice that the service interface accepts an Errors object. The idea here is that the registerAccount() method does a conditional registration—it registers the account if and only if there aren’t any validation errors, either present in the Errors object, or discovered inside the registerAccount() implementation (such as a duplicate username). The controller will call registerAccount() with its BindingResult object, which works fine because BindingResult extends Errors. You use Errors in the AccountService interface, though, rather than BindingResult, because the service tier doesn’t know anything about web binding.
Why call registerAccount() if there are already known errors?
It may seem odd to call the registerAccount() method if there are already errors in the Errors container. The reason: when doing form validation, you generally want to know about all validation errors, not just the first one. So you still check for duplicate usernames even if you already know, for example, that the passwords didn’t match.
The following listing is the account service implementation.

A good practice when writing service beans is to associate a read-only transaction definition at the class level . This provides a basic layer of safety because individual methods have to override the definition explicitly
in order to write to the persistent store. Here you have only one method, so it looks a little funny, but this way you won’t forget if you decide to add more methods.
Inside registerAccount(), you validate the username and save the account to the database if the entire account is valid
. The username validation
uses the finder you created to determine whether the username is a duplicate. If it is, then you use the errors object to reject the username, specifying the errors.duplicate error code (we’ll define that momentarily) and the username for token substitution.
Let’s quickly take care of that error message.
All you need to do is add a single error message to messages.properties:
The error.duplicate.account.username message code will match the error.duplicate error code as explained in recipe 4.3. Spring will substitute the username for the {0} when displaying the error message, because the username is the 0th element of the String[] you passed into rejectValue().
There isn’t much you need to do to the controller to make it save accounts, as you’ll see now.
To update the controller, you add a single line to the postRegistrationForm() method, and you add a helper method to convert the form bean into a domain object:
You’ll need to augment the existing configuration to support persistence. The main part of this effort involves adding a new Spring application context file. You’ll need to modify web.xml slightly as well. First let’s do the app context.
To add persistence to your registration form, you need to add several bits.

You declare a DataSource reference using a JNDI lookup at . You’ll need to consult the documentation for your servlet container to see what’s involved with exposing a DataSource with JNDI using that container. The sample code includes a Jetty configuration.
At you declare the JDBC template you’re using to set the user password. The Hibernate configuration is at
, and it’s set up for MySQL 5 in listing 4.15. You’ll need to modify that if you’re using a different RDBMS; see the Javadoc for the org.hibernate.dialect package for more options.
You define a Hibernate SessionFactory at , using the DataSource and configuration you just created. As its name suggests, the SessionFactory is a session source. Sometimes it creates brand-new sessions (for example, when starting a new transaction), and sometimes it returns sessions that have already been created (such as when executing DAO persistence operations).
The transaction manager provides (you guessed it) transaction management services. It knows, for example, how to start, suspend, and stop transactions. The HibernateTransactionManager implementation coordinates transaction management with Hibernate session management.
You use <context:component-scan> to discover DAOs and service beans . Component scanning interprets classes annotated with @Repository as DAOs and classes annotated with @Service as service beans.
Finally, at you use <tx:annotation-driven> to activate transactions. The specific details of that process are fairly involved, and there’s no need to dig into the details here, but the basic idea is that it causes Spring’s IOC container to wrap transaction-aware Spring AOP proxies around components marked up with the @Transactional annotation.[6] It does this using Spring AOP’s autoproxy facility.
6 In addition to Spring AOP proxies, AspectJ weaving is an option. See the reference documentation for <tx:annotation-driven> for more details.
Just one small tweak to go, and you’ll be ready to run the app.
All you need to do here is add a single configuration element to web.xml. This tells the Spring Web MVC DispatcherService where to find your beans-service.xml configuration:
With that, you should be ready to go. Try it out.
In this recipe we’ve shown how to save form data to a persistent store. That’s of course a common requirement, and now you have a good feel for how to do it. You even saw how to use Hibernate and JDBC together in cases where the form data doesn’t all fit nicely inside a single domain object.
Because our topic is web forms in general rather than user-registration forms in particular, we’ve neglected some persistence- and security-related topics that a real user form would take seriously. The good news is that we’ll address them in chapter 6. They’re the following:
- Spring Security integration— A key reason for user accounts is to support logins. Recipe 6.6 shows how to use the account data you’ve developed in chapter 4 as an authentication source.
- Hashing and salting passwords— It’s a poor security practice to save passwords as plaintext in the database, because that makes it easier for a malicious person to see those passwords and use them on other websites. (Users often use the same password for multiple websites.) You can use password hashing and salting to mitigate this issue. We’ll show how to hash and salt passwords in recipe 6.7.
In this chapter, you developed a basic registration form with several of the key features you’d expect such a form to have, including string externalization, validation, and persistence. Although we used user registration as an example, the topics we’ve treated are obviously general concerns when developing web-based forms.
In many cases, registration forms aren’t as simple as the one you developed in this chapter. Instead they carry the user through a series of steps, implemented as a web flow spanning multiple pages. In chapter 5 you’ll learn how to implement multistep flows using Spring Web Flow.