Spring MVCでバリデーションを利用する

1.イントロダクション

「バリデーション」とは「値のチェック」のこと。
Spring FrameworkではJSR-303 Bean Validation APIを利用する。

Bean Validation APIとは、Beanのバリデーションチェックを行うための機能のこと。
このバリデーションを設定しておくことで、フォームの値を自力でいちいちチェックしなくてもフレームワークが勝手にチェックしてくれるようになる。

2.準備

バリデーションに必要なライブラリを追加するために、pom.xmlに以下を追記する

・pom.xml

<!-- validation -->
<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>5.0.1.Final</version>
</dependency>

追記してmaven installすれば勝手に依存関係は解決される。

3.View

formタグを変更する。
具体的には、以下を追加する。

<form:errors path="*" element="div" />

コード全体はこちら。
・person-regist.jsp

<!DOCTYPE html>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<meta charset="utf-8">
<title>${title}</title>
</head>
<body>
<h2>${titleMessage}</h2>
<table>
<form:form modelAttribute="personForm" action="add">
<tr><td><form:errors path="*" element="div" /></td></tr>
<tr><td><form:label path="name">名前:</form:label></td>
<td><form:input path="name" size="20"/></td>
</tr>
<tr><td><form:label path="height">身長:</form:label></td>
<td><form:input path="height" size="6"/></td>
</tr>
<tr><td><input type="submit"></td></tr>
</form:form>
</table>
<c:if test="${dataList != null}" >
<table border="1">
<tr><th>名前</th><th>年齢</th></tr>
<c:forEach var="obj" items="${dataList}" varStatus="status">
<tr>
<td><c:out value="${obj.name }"/></td>
<td><c:out value="${obj.height }"/></td>
</tr>
</c:forEach>
</table>
</c:if>
</body>
</html>

4.Controller

package sample;
import java.util.ArrayList;
import java.util.List;
import javax.validation.Valid;
import model.PersonForm;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class PersonController {
private List<PersonForm> personList = new ArrayList<PersonForm>();
@RequestMapping(value = "/person", method = RequestMethod.GET)
public String person(Model model) {
model.addAttribute("title","バリデーション");
model.addAttribute("titleMessage","バリデーションを使ってみよう");
PersonForm personForm = new PersonForm();
model.addAttribute("personForm", personForm);
model.addAttribute("dataList", personList);
return "person-regist";
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String form(@Valid @ModelAttribute PersonForm personForm, BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("title", "[ERROR]");
model.addAttribute("titleMessage", "値をチェックしてください");
} else {
personList.add(personForm);
model.addAttribute("title","バリデーション");
model.addAttribute("titleMessage", "バリデーションしてみた!");
model.addAttribute("dataList", personList);
model.addAttribute("personForm", new PersonForm());
}
return "person-regist";
}
}

以下の、

@RequestMapping(value = "/add", method = RequestMethod.POST)
public String form(@Valid @ModelAttribute PersonForm personForm, BindingResult result, Model model) {

という部分がポイントで、
@Validというアノテーションを使うことで、バリデーションチェックを実行できる。

result.hasErrors()は、バリデーションエラーがあればtrue,なければfalseを返す。

5.Model

モデルのプロパティにアノテーションでバリデートを設定する。

・PersonForm.java

package model;
import java.util.Date;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotEmpty;
public class PersonForm {
@NotEmpty
private String name;
@NotNull
@Min(0)
@Max(300)
private Integer height;
private Date registerDate;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
public Date getRegisterDate() {
return registerDate;
}
public void setRegisterDate(Date registerDate) {
this.registerDate = registerDate;
}
}

ここでプロパティに@NotEmptyとか、@Min,@Maxがついていることに注目。

@NotEmptyは値が空でないことを確認する。
フォームから空で送信されたものは、「空の文字列」となるため、@NotEmptyを使う。
@NotNullはnullでないことを確認する。

@Minは整数値の最小値、@Maxは整数の最大値を指定する。

公式ドキュメントは以下。
http://docs.spring.io/spring/docs/3.0.0.RC3/reference/html/ch05s07.html

なお、Integer型のプロパティに@NotEmptyを設定したら、以下のようなエラーが出た。

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type: java.lang.Integer.

Integerには@NotNullを使うとよい。
参考)
http://stackoverflow.com/questions/5982741/error-no-validator-could-be-found-for-type-java-lang-integer

4.デモ

・初期画面
f:id:sho322:20140115201917j:plain
・異常な値を入力した場合
f:id:sho322:20140115201944j:plain
f:id:sho322:20140115201951j:plain

5.参考にした本

基礎的なことを省略せずに丁寧に解説してくれる素晴らしい本。
つまづかずに勉強することができている。