Basic web forms
4.1 Displaying a web form
PREREQUISITES
None
KEY TECHNOLOGIES
Spring Web MVC, Spring form tag library
This chapter covers
■ Building a web form
■ Externalizing strings in a view
■ Validating and saving form data
Background
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 registra-tion form.
Problem
Create a web-based form.
Solution
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 confirma-tion page.
It won’t hurt to have a visual on the UI you’re planning to create in this recipe. Fig-ure 4.1 shows what you’re aiming for.
Let’s begin by creating a form bean for your user accounts.
CREATING AN ACCOUNT FORM BEAN
You use a form bean to store form data, as shown in the following listing.
package com.springinpractice.ch04.web;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class AccountForm {
private String username, password, confirmPassword, firstName, lastName, email;
private boolean marketingOk = true;
private boolean acceptTerms = false;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; } ... other getter/setter pairs ...
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) .append("username", username)
.append("firstName", firstName) .append("lastName", lastName) .append("email", email)
.append("marketingOk", marketingOk) .append("acceptTerms", acceptTerms) .toString();
} }
Listing 4.1 AccountForm.java, a form bean for user accounts
Demographic data
B
Marketing preference
C
Legal confirmation
D
toString() implementation
E
AccountForm is a POJO.1 It has properties for personal
B
, marketingC
, and legalD
data. These are typical concerns when modeling user accounts. You also include a descriptive toString() method
E
, 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
You have a form bean, but without a web controller, it’s inert. Let’s take care of that.
CREATING A WEB CONTROLLER
Your account controller, which appears in the following listing, handles form delivery and processing.
1 See http://en.wikipedia.org/wiki/Plain_Old_Java_Object.
2 Disclaimer: We aren’t lawyers! Consult a qualified legal expert if necessary.
Figure 4.1 The simple web-based registration form that you’ll build in this recipe
package com.springinpractice.ch04.web;
LoggerFactory.getLogger(AccountController.class);
@RequestMapping(value = "new", method = RequestMethod.GET) public String getRegistrationForm(Model model) { model.addAttribute("account", new AccountForm());
return "users/registrationForm";
}
@RequestMapping(value = "", method = RequestMethod.POST) public String postRegistrationForm(AccountForm form) { log.info("Created registration: {}", form);
return "redirect:registration_ok";
} }
At
B
the @Controller annotation tells Spring that this is a web controller. You estab-lish a base path for request mapping using the @RequestMapping annotationC
. This path contextualizes paths declared at the method level. AtD
you’re not implement-ing any special interfaces or extendimplement-ing special classes.You serve the empty form bean at
E
. 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-method-level mapping rather than refine it, place a slash in front of the method-level mapping.) The method itself places a new Account-Form instance on the model under the key account and returns the view name.
You process form submissions at
F
, 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 registeringG
. 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.
CREATING THE VIEW PAGES
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.
Listing 4.2 AccountController.java to handle user registrations
Declares
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head><title>New User Registration</title></head>
<body>
<form:form action="." modelAttribute="account">
<h1>New User Registration</h1>
<div>Username: <form:input path="username" /></div>
<div>Password: <form:password path="password" /></div>
<div>Confirm password: <form:password path="confirmPassword" /></div>
<div>E-mail address: <form:input path="email" /></div>
<div>First name: <form:input path="firstName" /></div>
<div>Last name: <form:input path="lastName" /></div>
<div><form:checkbox id="marketingOk" path="marketingOk" />
Please send me product updates by e-mail.</div>
<div><form:checkbox id="acceptTerms" path="acceptTerms" />
I accept the <a href="#">terms of use</a>.</div>
<div><input type="submit" value="Register" /></div>
</form:form>
</body>
</html>
The registration page uses the form
B
tag to create an HTML form. You use action="." to post the form submission to /main/users/. The modelAttribute attri-bute 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.
Listing 4.3 registrationForm.jsp: view to display your registration form
Renders