• No results found

Form validation

In document Spring (Page 187-190)

Enhancing Spring MVC applications with Web Flow

5.6 Form validation

PREREQUISITES

Form Data Binding

KEY TECHNOLOGIES

SWF, Spring Validation, JSR-303 Bean Validation API Background

Users interact with websites by clicking links and submitting forms. All but the simplest systems validate their form data to ensure that information is captured in the format that is expected and that any additional rules, such as required fields, are enforced.

Problem

When a user submits a form, you would like to validate the data that was submitted before doing additional processing. If validation errors occur, you would like to let the user know in a user-friendly way so they may make any necessary corrections before continuing.

Solution

JSR-303 defines a standardized metadata model and API for Java bean validation that allows you to define validation constraints without tying you to a specific application tier or programming model. The JSR-303 Bean Validation API became fully supported in Spring 3.0 and has been available to Spring MVC applications for quite some time.

Information on how to configure JSR-303 validation with Spring MVC was covered in section 4.2. At the time of this writing, version 2.3.0 of SWF has been released and has added support for JSR-303–style validation.

If you’ve already configured JSR-303 support as part of your Spring MVC setup, you can skip the next section. If not, let’s get started.

BOOTSTRAPPING A JSR-303 IMPLEMENTATION

As you’ve come to expect, Spring has made bootstrapping a JSR-303 implementation easy. All that is necessary is to create a single bean definition and have a JSR-303 pro-vider on the classpath. You’ll use Hibernate Validator, the JSR-303 reference imple-mentation, here. Validate that you have the following dependency in your POM file:

<dependency>

<groupId>org.hibernate</groupId>

<artifactId>hibernate-validator</artifactId>

<version>4.1.0.Beta1</version>

</dependency>

This Maven dependency adds the hibernate-validator-4.1.0.Beta1.jar file to your class-path. Once this is done, you can add the following bean definition to your Spring con-figuration. If you’re following along with the source code from the project (sip05, branch: 06), this is already done for you:

<bean id="validator" class="org.springframework.validation.

beanvalidation.LocalValidatorFactoryBean"/>

LocalValidatorFactoryBean implements three separate interfaces: javax.valida-tion.ValidatorFactory, javax.validation.Validator, and org.springframe-work.validation.Validator. Many applications use JSR-303 validation in addition to Spring validation. The added flexibility allows you to use the same bean definition for both.

CONFIGURING SWF TO USE JSR-303 VALIDATION

Now that your JSR-303 validator is configured, you need to make SWF aware of it. To do this, add a reference to your new validator to the flow-builder-services JSR-303 annotations to a class. The following listing shows the code.

// Source project: sip05, branch: 06 (Maven Project) package com.springinpractice.ch05.form;

public class AccountForm implements Serializable { private static final long serialVersionUID = 1L;

protected Guardian guardian = new Guardian();

protected Player child = new Player();

protected String confirmPassword;

protected String confirmEmail;

public AccountForm() {}

@Valid public Guardian getGuardian() {

return guardian;

}

public void setGuardian(Guardian guardian) { this.guardian = guardian;

public void setChild(Player child) { this.child = child;

}

@NotEmpty public String getConfirmPassword() { return confirmPassword;

} ...

}

You use two different annotations. The @Valid annotation at

B

tells the validator to validate the Guardian child class and aggregate any error messages with those from the AccountForm class as well. You see similar behavior at

C

with the Player class.

Note that like JPA annotations, JSR-303 annotations can be placed on the attribute or on the getter method. For a more detailed discussion of the built-in JSR-303 con-straints and the JSR 303 specification, see http://jcp.org/en/jsr/detail?id=303. Note that the annotation at

D

isn’t part of the JSR-303 specification. Instead, it’s a part of the Hibernate Validator framework that is the reference implementation for JSR 303.

For more information on the Hibernate Validator, see the documentation at http://

hibernate.org/subprojects/validator.

Now let’s talk about how you can customize any resulting error messages.

MAPPING ERROR CODES TO MESSAGES IN A PROPERTIES FILE

When one or more validation rules fail, the validator generates a set of keys that Spring resolves to localized messages. Looking at example messages from the demo applica-tion’s messages.properties file, you’ll find that the naming convention is intuitive:

accountForm.confirmPassword.NotEmpty=The guardian's password confirmation

is required

accountForm.confirmEmail.NotEmpty=The guardian's email confirmation is

required ...

accountForm.child.firstName.NotEmpty=The child's first name is required accountForm.child.lastName.NotEmpty=The child's last name is required accountForm.child.birthDate.NotNull=The child's birth date is required accountForm.child.birthDate.typeMismatch=The child's birth date must be in

the format mm/dd/yyyy

In this example, the @NotEmpty annotation generates .NotEmpty, which is appended to the end of the full EL-like path of the property. To create a flow-specific message bundle, add a default message.properties file or a localized version of this file in the same directory as the flow-definition file. No additional configuration is necessary.

When a model is specified in a view state, validation follows the binding process.

You can suppress this validation process by specifying validation="false" in the transition element. Look at the following example:

<view-state id="newAccountForm" model="accountForm">

<transition on="next" to="confirmNewAccount"/>

<transition on="back" to="somePreviousState" validate="false" />

</view-state>

Provided by Hibernate Validator

D

When transitioning to next, information is bound to accountForm and validated. If an error occurs, the user is returned to the newAccountForm view where the errors are displayed. Because displaying form errors was covered in section 4.2, we won’t discuss it again here. When transitioning to back, binding still occurs, but the data is no lon-ger validated. Alternatively, you could specify bind="false" and omit the binding and validation process entirely.

You can test your handiwork by pointing your browser at http://localhost:8080/

sip/registration (adjusting for host name and port number) and then navigating to the New Account Creation form.

In document Spring (Page 187-190)