春のバリデーションの例 – Spring MVCフォームのバリデーター

任意のウェブアプリケーションでユーザーの入力を受け入れる際には、それらを検証する必要が生じます。JavaScriptを使用してクライアント側でユーザーの入力を検証することができますが、ユーザーがJavaScriptを無効にしている場合にも、サーバー側でそれらを検証する必要があります。これにより、処理するデータが有効であることを確認できます。

スプリングのバリデーション

デフォルトでSpring MVC Frameworkでは、JSR-303の仕様をサポートしており、Spring MVCアプリケーションにはJSR-303とその実装に関する依存関係を追加するだけで十分です。Springでは、@ValidatorアノテーションとBindingResultクラスも提供されており、これらを使用することで、コントローラのリクエストハンドラメソッドでValidatorの実装によって発生したエラーを取得することができます。カスタムのバリデータ実装を2つの方法で作成することができます。1つは、JSR-303の仕様に準拠するアノテーションを作成し、そのバリデータクラスを実装する方法です。2つ目のアプローチは、org.springframework.validation.Validatorインターフェースを実装し、@InitBinderアノテーションを使用してControllerクラスでバリデータとして設定する方法です。Spring Tool SuiteでシンプルなSpring MVCプロジェクトを作成しましょう。ここでは、JSR-303の仕様とその実装アーティファクトであるhibernate-validatorを使用します。アノテーションベースのフォームバリデーションを行い、JSR-303の仕様に基づいた独自のカスタムバリデータを作成します。また、Validatorインターフェースを実装して独自のカスタムバリデータクラスを作成し、それをコントローラのハンドラメソッドの1つで使用します。最終的なプロジェクトは以下の画像のようになります。それでは、各コンポーネントを1つずつ見ていきましょう。

Spring MVC フォームバリデータ

最終的なpom.xmlファイルは以下のようになります。Spring MVCの基本的なアーティファクトに加えて、プロジェクトにはvalidation-apiとhibernate-validatorの依存関係もあります。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.scdev</groupId>
	<artifactId>spring</artifactId>
	<name>SpringFormValidation</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.7</java-version>
		<org.springframework-version>4.0.2.RELEASE</org.springframework-version>
		<org.aspectj-version>1.7.4</org.aspectj-version>
		<org.slf4j-version>1.7.5</org.slf4j-version>
	</properties>
	<dependencies>
	<!-- Form Validation using Annotations -->  
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.1.0.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>4.1.0.Final</version>
		</dependency>
		
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>

		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>

		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-eclipse-plugin</artifactId>
				<version>2.9</version>
				<configuration>
					<additionalProjectnatures>
						<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
					</additionalProjectnatures>
					<additionalBuildcommands>
						<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
					</additionalBuildcommands>
					<downloadSources>true</downloadSources>
					<downloadJavadocs>true</downloadJavadocs>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
					<compilerArgument>-Xlint:all</compilerArgument>
					<showWarnings>true</showWarnings>
					<showDeprecation>true</showDeprecation>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>exec-maven-plugin</artifactId>
				<version>1.2.1</version>
				<configuration>
					<mainClass>org.test.int1.Main</mainClass>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

展開記述子

STSからSpring MVCプロジェクトを作成すると、2つのコンテキスト設定ファイルが作成されます。私はそれを少し整理し、1つのSpring Bean設定ファイルにまとめました。最終的なweb.xmlファイルは以下のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	
	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/spring.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

春の豆の設定ファイル

通常、私たちは最後にスプリングの配線を確認しますが、今回はスプリングのbean設定ファイルにはほとんどの設定がありません。最終的なspring.xmlファイルは以下のようになります。

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="https://www.springframework.org/schema/beans"
	xmlns:context="https://www.springframework.org/schema/context"
	xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<beans:bean id="employeeValidator" class="com.scdev.spring.form.validator.EmployeeFormValidator" />
	
	<beans:bean id="messageSource"
		class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
		<beans:property name="basename" value="classpath:message" />
		<beans:property name="defaultEncoding" value="UTF-8" />
	</beans:bean>
	
	<context:component-scan base-package="com.scdev.spring" />
	
</beans:beans>

この場合、注目すべき重要なポイントは、controllerの1つにインジェクションされるemployeeValidator beanと、リソースバンドルからローカライズデータを読み込むためのmessageSource beanです。その他の部分は、アノテーションのサポートやビューリゾルバ、Controllerクラスやその他のコンポーネントのスキャン用のパッケージの提供を行います。

モデルクラス

このプロジェクトには2つのモデルクラスがあります-最初のクラスでは、JSR-303のアノテーションと独自のアノテーションベースのバリデータを使用し、2番目のクラスでは当社のバリデータ実装のみを使用します。Customer.javaコード:

package com.scdev.spring.form.model;

import java.util.Date;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;

import com.scdev.spring.form.validator.Phone;

public class Customer {

	@Size(min=2, max=30) 
    private String name;
     
    @NotEmpty @Email
    private String email;
     
    @NotNull @Min(18) @Max(100)
    private Integer age;
     
    @NotNull
    private Gender gender;
     
    @DateTimeFormat(pattern="MM/dd/yyyy")
    @NotNull @Past
    private Date birthday;
    
    @Phone
    private String phone;
    
    public enum Gender {
		MALE, FEMALE
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public Gender getGender() {
		return gender;
	}

	public void setGender(Gender gender) {
		this.gender = gender;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}
	
}

JSR-303に追加された、Hibernate validatorの実装によって提供されるアノテーションである@Email、@NotEmpty、@DateTimeFormatを使用していることに注意してください。使用しているJSR-303のアノテーションには、@Size、@NotNullなどがあります。@PhoneアノテーションはJSR-303仕様に基づいて独自に実装されたものであり、次のセクションで詳しく調べます。Employee.javaコード:

package com.scdev.spring.form.model;

public class Employee {

	private int id;
	private String name;
	private String role;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	
}

従業員は標準的なJava Beanであり、従業員のフォームをカスタムのバリデータ実装を使って検証します。

カスタムバリデータの実装

Phone.javaのコード :

package com.scdev.spring.form.validator;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target( { ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Phone {
 
     
    String message() default "{Phone}";
     
    Class<?>[] groups() default {};
     
    Class<? extends Payload>[] payload() default {};
      
}

ほとんどのパートはJSR-303の仕様に準拠するための定型のコードです。最も重要な部分は@Constraintアノテーションで、バリデーションに使用するクラス、つまりPhoneValidatorを指定します。PhoneValidator.javaのコードです。

package com.scdev.spring.form.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PhoneValidator implements ConstraintValidator<Phone, String> {

	@Override
	public void initialize(Phone paramA) {
	}

	@Override
	public boolean isValid(String phoneNo, ConstraintValidatorContext ctx) {
		if(phoneNo == null){
			return false;
		}
		//validate phone numbers of format "1234567890"
        if (phoneNo.matches("\\d{10}")) return true;
        //validating phone number with -, . or spaces
        else if(phoneNo.matches("\\d{3}[-\\.\\s]\\d{3}[-\\.\\s]\\d{4}")) return true;
        //validating phone number with extension length from 3 to 5
        else if(phoneNo.matches("\\d{3}-\\d{3}-\\d{4}\\s(x|(ext))\\d{3,5}")) return true;
        //validating phone number where area code is in braces ()
        else if(phoneNo.matches("\\(\\d{3}\\)-\\d{3}-\\d{4}")) return true;
        //return false if nothing matches the input
        else return false;
	}

}

私たちのJSR-303の仕様バリデーターの実装は、javax.validation.ConstraintValidatorインターフェースを実装する必要があります。もしDataSourceのようなリソースを使用している場合、それらをinitialize()メソッドで初期化できます。バリデーションメソッドはisValidであり、データが有効な場合はtrueを返す必要があります。正規表現について初めての方は、Java正規表現チュートリアルで詳細を読むことができます。EmployeeFormValidator.javaクラスのコードです。

package com.scdev.spring.form.validator;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.scdev.spring.form.model.Employee;

public class EmployeeFormValidator implements Validator {

	//which objects can be validated by this validator
	@Override
	public boolean supports(Class<?> paramClass) {
		return Employee.class.equals(paramClass);
	}

	@Override
	public void validate(Object obj, Errors errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "id.required");
		
		Employee emp = (Employee) obj;
		if(emp.getId() <=0){
			errors.rejectValue("id", "negativeValue", new Object[]{"'id'"}, "id can't be negative");
		}
		
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "name.required");
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "role", "role.required");
	}
}

EmployeeFormValidatorは、Spring Frameworkに特化したバリデータの実装です。supports()メソッドの実装により、このバリデーションが使用できるオブジェクトをSpring Frameworkが知ることができます。私たちはvalidate()メソッドを実装し、フィールドのバリデーションが失敗した場合にエラーを追加します。Springは、nullや空などの基本的なバリデーションのためにorg.springframework.validation.ValidationUtilsユーティリティクラスを提供しています。このメソッドが返されると、Spring FrameworkはErrorsオブジェクトをBindingResultオブジェクトにバインドし、コントローラーハンドラーメソッドで使用します。ValidationUtils.rejectIfEmptyOrWhitespace()の最後の引数は、メッセージリソースのキー名を取ります。これにより、ユーザーに対してローカライズされたエラーメッセージを提供することができます。Springに関する詳細な情報は、「Spring i18n Example」を参照してください。

コントローラークラス

私たちには2つのコントローラクラスがあります。1つは注釈ベースのフォームのバリデーションを行うためのもので、もう1つはカスタムバリデータのためのものです。CustomerController.javaクラスのコードです。

package com.scdev.spring.form.controllers;

import java.util.HashMap;
import java.util.Map;

import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.scdev.spring.form.model.Customer;

@Controller
public class CustomerController {

	private static final Logger logger = LoggerFactory
			.getLogger(CustomerController.class);
	
	private Map<String, Customer> customers = null;
	
	public CustomerController(){
		customers = new HashMap<String, Customer>();
	}

	@RequestMapping(value = "/cust/save", method = RequestMethod.GET)
	public String saveCustomerPage(Model model) {
		logger.info("Returning custSave.jsp page");
		model.addAttribute("customer", new Customer());
		return "custSave";
	}

	@RequestMapping(value = "/cust/save.do", method = RequestMethod.POST)
	public String saveCustomerAction(
			@Valid Customer customer,
			BindingResult bindingResult, Model model) {
		if (bindingResult.hasErrors()) {
			logger.info("Returning custSave.jsp page");
			return "custSave";
		}
		logger.info("Returning custSaveSuccess.jsp page");
		model.addAttribute("customer", customer);
		customers.put(customer.getEmail(), customer);
		return "custSaveSuccess";
	}

}

アノテーションベースのフォームバリデーションを使用する場合、コントローラーハンドラメソッドの実装にわずかな変更を加えるだけで動作させることができます。まず、@Validアノテーションでバリデートしたいモデルオブジェクトにアノテーションを付ける必要があります。そしてメソッドにBindingResult引数を持たせる必要があります。Springはエラーメッセージを取得するためにこれを自動的にポピュレートします。ハンドラーメソッドのロジックは非常にシンプルです。エラーがあれば同じページを返し、エラーがなければユーザーを成功ページにリダイレクトします。もう1つ重要なポイントは、モデルに「customer」という属性を追加していることです。これはSpringフレームワークに使用するモデルオブジェクトを知らせるために必要です。これを行わないと、フォームデータへのオブジェクトバインディングが行われず、フォームのバリデーションが機能しません。EmployeeController.javaクラスのコード:

package com.scdev.spring.form.controllers;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.scdev.spring.form.model.Employee;

@Controller
public class EmployeeController {

	private static final Logger logger = LoggerFactory
			.getLogger(EmployeeController.class);

	private Map<Integer, Employee> emps = null;

	@Autowired
	@Qualifier("employeeValidator")
	private Validator validator;

	@InitBinder
	private void initBinder(WebDataBinder binder) {
		binder.setValidator(validator);
	}

	public EmployeeController() {
		emps = new HashMap<Integer, Employee>();
	}

	@ModelAttribute("employee")
	public Employee createEmployeeModel() {
		// ModelAttribute value should be same as used in the empSave.jsp
		return new Employee();
	}

	@RequestMapping(value = "/emp/save", method = RequestMethod.GET)
	public String saveEmployeePage(Model model) {
		logger.info("Returning empSave.jsp page");
		return "empSave";
	}

	@RequestMapping(value = "/emp/save.do", method = RequestMethod.POST)
	public String saveEmployeeAction(
			@ModelAttribute("employee") @Validated Employee employee,
			BindingResult bindingResult, Model model) {
		if (bindingResult.hasErrors()) {
			logger.info("Returning empSave.jsp page");
			return "empSave";
		}
		logger.info("Returning empSaveSuccess.jsp page");
		model.addAttribute("emp", employee);
		emps.put(employee.getId(), employee);
		return "empSaveSuccess";
	}
}

カスタムバリデータを使用するために、まずコントローラークラスに注入する必要があります。Springのbeanの自動配線を使用して、@Autowiredと@Qualifierの注釈を使用してこれを実現しています。次に、WebDataBinderを引数とするメソッドを持つ必要があり、カスタムバリデータを設定します。このメソッドは@InitBinderの注釈で指定します。@ModelAttributeを使用することも、自分のbeanオブジェクトをモデルに追加する別の方法です。それ以外のコードは、顧客コントローラーの実装と似ています。

フォームの検証エラーメッセージのリソースバンドル

メッセージの種類が異なるバリデーションエラーに使用されるリソースバンドルを確認する時が来ました。message_en.propertiesファイルです。

#application defined error messsages
id.required=Employee ID is required
name.required=Employee Name is required
role.required=Employee Role is required
negativeValue={0} can't be negative or zero

#Spring framework error messages to be used when conversion from form data to bean fails
typeMismatch.int={0} Value must be an integer
typeMismatch.java.lang.Integer={0} must be an integer
typeMismatch={0} is of invalid format

#application messages for annotations, {ValidationClass}.{modelObjectName}.{field}
#the {0} is field name, other fields are in alphabatical order, max and then min  
Size.customer.name=Customer {0} should be between {2} and {1} characters long
NotEmpty.customer.email=Email is a required field
NotNull.customer.age=Customer {0} should be in years

#Generic annotation class messages
Email=Email address is not valid
NotNull=This is a required field
NotEmpty=This is a required field
Past=Date should be Past

#Custom validation annotation
Phone=Invalid format, valid formats are 1234567890, 123-456-7890 x1234

ここでメッセージのキーの詳細をコメント内で提供しているため、ここでは省略します。ここで特に注意すべき重要なポイントは、メッセージの検索方法です。最初にキー名 {ValidationClass}.{modelObjectName}.{field} が検索され、見つからない場合は {ValidationClass}.{modelObjectName} が検索されます。それも見つからない場合は、最後に {ValidationClass} のキーが検索されます。何も見つからない場合は、提供されたデフォルトメッセージが返されます。Spring ローカライゼーションの例でリソースメッセージについてもっと詳しく読むことができます。

フォームとエラーを含むページを表示する

私たちはSpringフレームワークのバリデーション実装を使用しているため、エラーを取得し、フォームのビーンと変数名を設定するためにSpring Formタグを使用する必要があります。以下に、custSave.jspファイルのコードが示されています。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="https://www.springframework.org/tags/form"
	prefix="springForm"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Customer Save Page</title>
<style>
.error {
	color: #ff0000;
	font-style: italic;
	font-weight: bold;
}
</style>
</head>
<body>

	<springForm:form method="POST" commandName="customer"
		action="save.do">
		<table>
			<tr>
				<td>Name:</td>
				<td><springForm:input path="name" /></td>
				<td><springForm:errors path="name" cssClass="error" /></td>
			</tr>
			<tr>
				<td>Email:</td>
				<td><springForm:input path="email" /></td>
				<td><springForm:errors path="email" cssClass="error" /></td>
			</tr>
			<tr>
				<td>Age:</td>
				<td><springForm:input path="age" /></td>
				<td><springForm:errors path="age" cssClass="error" /></td>
			</tr>
			<tr>
				<td>Gender:</td>
				<td><springForm:select path="gender">
						<springForm:option value="" label="Select Gender" />
						<springForm:option value="MALE" label="Male" />
						<springForm:option value="FEMALE" label="Female" />
					</springForm:select></td>
				<td><springForm:errors path="gender" cssClass="error" /></td>
			</tr>
			<tr>
				<td>Birthday:</td>
				<td><springForm:input path="birthday" placeholder="MM/dd/yyyy"/></td>
				<td><springForm:errors path="birthday" cssClass="error" /></td>
			</tr>
			<tr>
				<td>Phone:</td>
				<td><springForm:input path="phone" /></td>
				<td><springForm:errors path="phone" cssClass="error" /></td>
			</tr>
			<tr>
				<td colspan="3"><input type="submit" value="Save Customer"></td>
			</tr>
		</table>

	</springForm:form>

</body>
</html>

commandName=”customer”は、フォームオブジェクトが公開されるモデル属性の名前を設定するために使用されます。デフォルト値は「command」ですので、コントローラクラスで使用しているモデル属性の名前に設定する必要があります。springForm:errorsは、ページが表示される際に見つかったエラーを表示するために使用されます。path属性は、データバインディングに使用するオブジェクトプロパティを定義するために使用されます。コードの残りは、エラーメッセージのスタイリングのためにいくつかのCSSを含んだ標準的なHTMLです。custSaveSuccess.jspファイルは以下の通りです。

<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fmt" uri="https://java.sun.com/jsp/jstl/fmt" %>

<%@ page session="false" %>
<html>
<head>
	<title>Customer Saved Successfully</title>
</head>
<body>
<h3>
	Customer Saved Successfully.
</h3>

<strong>Customer Name:${customer.name}</strong><br>
<strong>Customer Email:${customer.email}</strong><br>
<strong>Customer Age:${customer.age}</strong><br>
<strong>Customer Gender:${customer.gender}</strong><br>
<strong>Customer Birthday:<fmt:formatDate value="${customer.birthday}" type="date" /></strong><br>

</body>
</html>

もしバリデーションエラーがなく、このページがレスポンスとして返される場合、顧客の値が表示されるシンプルなJSPページです。その名前はempSave.jspです。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="https://www.springframework.org/tags/form"
	prefix="springForm"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Employee Save Page</title>
<style>
.error {
	color: #ff0000;
	font-style: italic;
	font-weight: bold;
}
</style>
</head>
<body>

	<springForm:form method="POST" commandName="employee"
		action="save.do">
		<table>
			<tr>
				<td>Employee ID:</td>
				<td><springForm:input path="id" /></td>
				<td><springForm:errors path="id" cssClass="error" /></td>
			</tr>
			<tr>
				<td>Employee Name:</td>
				<td><springForm:input path="name" /></td>
				<td><springForm:errors path="name" cssClass="error" /></td>
			</tr>
			<tr>
				<td>Employee Role:</td>
				<td><springForm:select path="role">
						<springForm:option value="" label="Select Role" />
						<springForm:option value="ceo" label="CEO" />
						<springForm:option value="developer" label="Developer" />
						<springForm:option value="manager" label="Manager" />
					</springForm:select></td>
				<td><springForm:errors path="role" cssClass="error" /></td>
			</tr>
			<tr>
				<td colspan="3"><input type="submit" value="Save"></td>
			</tr>
		</table>

	</springForm:form>

</body>
</html>

empSaveSuccess.jspファイル:

<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
	<title>Employee Saved Successfully</title>
</head>
<body>
<h3>
	Employee Saved Successfully.
</h3>

<strong>Employee ID:${emp.id}</strong><br>
<strong>Employee Name:${emp.name}</strong><br>
<strong>Employee Role:${emp.role}</strong><br>

</body>
</html>

Spring MVCのフォームバリデーションアプリケーションをテストしてください。

私たちのアプリケーションは、展開およびテストを実行する準備ができていますので、お好きなサーブレットコンテナに展開してください。私はApache Tomcat 7を使用しており、以下の画像はバリデーションエラーメッセージを含むいくつかのページを示しています。入力データに応じて、異なるエラーメッセージが表示される場合もあります。これでSpring MVCフォームのバリデーションについての異なる方法とローカライズされたエラーメッセージ用のリソースバンドルを使った説明は終わりです。以下のリンクからサンプルプロジェクトをダウンロードし、さらに学ぶために遊びながらお使いいただけます。

「Spring Form Validation プロジェクトをダウンロード」

コメントを残す 0

Your email address will not be published. Required fields are marked *