【Spring】Validation（入力チェック）

# 概要

当記事では、
　　・標準機能のValidation
　　・独自実装Validation
の実装方法について説明します。

# 標準機能のValidation
必須チェックを実装したい場合を例にすると、
「javax.validation.constraints.NotEmpty」など
下記の「 <span>@</span>NotEmpty(message = "入力してください。") 」のように、
指定することで簡単に実装することができます。
```
@NotEmpty(message = "入力してください。")
public String mailAddress;
```


# 独自Validation


## アノテーション実装
```/ValidationDemo/src/main/java/com/example/demo/validation/UnavailableString.java
package com.example.demo.validation;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Constraint(validatedBy = { UnavailableStringValidator.class })
public @interface UnavailableString {
	String message() default "使用禁止文字を除去してください。";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};

	String[] strings();
}
```

## チェック処理実装
```/ValidationDemo/src/main/java/com/example/demo/validation/UnavailableStringValidator.java
package com.example.demo.validation;

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

public class UnavailableStringValidator implements ConstraintValidator<UnavailableString, String> {

	private String[] strings;

	@Override
	public void initialize(UnavailableString unavailableString) {
		strings = unavailableString.strings();
	}

	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
		for (String str : strings) {
			if (value.contains(str)) {
				return false;
			}
		}

		return true;
	}
}
```

## アノテーション指定
上記で実装したアノテーションを、
下記の「<span>@</span>UnavailableString(strings = { "@","," })」のように、
フィールドに対して指定します。
※「strings」に指定した「@」と「,」が禁止文字になります。
```
@UnavailableString(strings = { "@","," })
public String name;
```

# 動作検証のための実装例
```/ValidationDemo/src/main/java/com/example/demo/user/Check.java
package com.example.demo.user;

import javax.validation.constraints.NotEmpty;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.example.demo.validation.UnavailableString;

@Controller
@RequestMapping("user/check")
public class Check {

	/**
	 * ユーザチェック　入力
	 *
	 * @param model
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/input", method = RequestMethod.GET)
	public String input() {
		return "user/check/input";
	}

	/**
	 * ユーザチェック　結果
	 *
	 * @param company
	 * @param result
	 * @param model
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/result", method = RequestMethod.POST)
	public String result(@Validated @ModelAttribute User user, BindingResult result, Model model) throws Exception {
		model.addAttribute("user", user);

		return "user/check/result";
	}

	/**
	 * ユーザ
	 */
	public class User {

		@UnavailableString(strings = { "@","," })
		@NotEmpty(message = "入力してください。")
		public String name;

		@NotEmpty(message = "入力してください。")
		public String mailAddress;

		/**
		 * コンストラクタ
		 *
		 * @param name
		 * @param mailAddress
		 * @param mailAddressConfirm
		 */
		public User(String name, String mailAddress, String mailAddressConfirm) {
			this.name = name;
			this.mailAddress = mailAddress;
		}

		public String getName() {
			return name;
		}

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

		public String getMailAddress() {
			return mailAddress;
		}

		public void setMailAddress(String mailAddress) {
			this.mailAddress = mailAddress;
		}
	}
}
```

```/ValidationDemo/src/main/java/com/example/demo/validation/UnavailableString.java
package com.example.demo.validation;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

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

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Constraint(validatedBy = { UnavailableStringValidator.class })
public @interface UnavailableString {
	String message() default "使用禁止文字を除去してください。";

	Class<?>[] groups() default {};

	Class<? extends Payload>[] payload() default {};

	String[] strings();
}
```
```/ValidationDemo/src/main/java/com/example/demo/validation/UnavailableStringValidator.java
package com.example.demo.validation;

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

public class UnavailableStringValidator implements ConstraintValidator<UnavailableString, String> {

	private String[] strings;

	@Override
	public void initialize(UnavailableString unavailableString) {
		strings = unavailableString.strings();
	}

	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
		for (String str : strings) {
			if (value.contains(str)) {
				return false;
			}
		}

		return true;
	}
}
```

```/ValidationDemo/src/main/resources/templates/user/check/input.html
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>ValidationDemo - Input</title>
</head>
<body>
	<form action="result" method="POST">
		<div>
			name:<input type="text" name="name" />
		</div>
		
		<div>
			mailAddress:<input type="text" name="mailAddress" />
		</div>
	
		<button type="submit">送信</button>
	</form>
</body>
</html>
```

```/ValidationDemo/src/main/resources/templates/user/check/result.html
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>ValidationDemo - Result</title>
	<style>
		table{
		  border-collapse:collapse;
		}
		 
		table th{
		  border:1px solid #000066;
		  background:royalblue;
		}
		 
		table th,table td{
		  border:1px solid #000066;
		  background:#ffffff;
		}
	</style>
</head>

<body>
	<table>
		<thead>
			<tr>
				<th>#</th>
				<th>項目</th>
				<th>エラーメッセージ</th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>1</td>
				<td>name</td>
				<td><p th:errors="*{user.name}"></p></td>
			</tr>
			<tr>
				<td>2</td>
				<td>mailAddress</td>
				<td><p th:errors="*{user.mailAddress}"></p></td>
			</tr>
		</tbody>
	</table>
</body>
</html>
```


# 動作確認

アプリを起動後、http://localhost:8080/user/check/inputを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/d6559a85-88c7-ebbc-2b7b-a5f9e643dddf.png)

下記の要領で入力し、「送信」ボタンをクリック。
name・・・禁止文字「@」を含む文字列を指定
mailAddress・・・未指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/838d67c3-7546-2ddf-b331-d177c5f65516.png)

* name
「<span>@</span>UnavailableString(strings = { "@","," })」で指定したチェックが効き、
禁止文字エラーが表示されます。
* mailAddress
「<span>@</span>NotEmpty(message = "入力してください。")」で指定したチェックが効き、
未入力エラーが表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/c3b693b0-c44c-746a-a229-f9dcc98da90b.png)