【SpringBoot】Validation

# Validation

Validationとはフォームで送られたデータを検証する機能です。

フォームのあるシステムでは必ず実装されている機能で、不正なデータによる予期しない挙動を防ぐものです。

先ほど作成したCREATEとUPDATEに実際に実装してみましょう。

```diff_java:/demo/src/main/java/com/example/demo/TodoController.java
	package com.example.demo;	
		
	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.GetMapping;	
	import org.springframework.web.bind.annotation.PathVariable;	
	import org.springframework.web.bind.annotation.PostMapping;	
	import org.springframework.web.servlet.ModelAndView;	
		
	@Controller	
	public class TodoController {	
	    	
	    private final TodoRepository repository; // final修飾子のフィールド変数	
	    	
	    //　コンストラクタ	
	    public TodoController(TodoRepository repository) { 	
	        this.repository = repository;	
	    }	
	    	
	    @GetMapping() // GETリクエスト処理	
	    public ModelAndView index () {	
	        //  テンプレートで利用するデータと、Viewに関する情報を管理するオブジェクト	
	        ModelAndView mav = new ModelAndView();	
+	        	
+	        // Entityインスタンス     	
+	        Todo todo = new Todo();	
+	        	
+	        //　エラーメッセージ表示のため追加      	
+	        mav.addObject("todo", todo);	
+	        	
	        //　keyがtodosのViewで使用できるデータを追加       	
	        mav.addObject("todos", repository.findAll());	
	        // Viewファイル名を設定     	
	        mav.setViewName("index");	
	        return mav;	
	    }	
	    	
	    @PostMapping() // POSTリクエスト処理	
+	     // フォームのデータ検証結果を保持するオブジェクト	
-	    public String store (Todo todo) {	
+	    public String store (@Validated Todo todo, BindingResult result, Model model) {	
+	        if (result.hasErrors()) {	
+	            /*　keyがtodosのViewで使用できるデータを追加　	
+	             *戻り値がStringのためModelで対応	
+	             */         	
+	            model.addAttribute("todos", repository.findAll());	
+	            return "index";	
+	        }	
+	        	
	        // 送られてきたformDataデータを保存	
	        repository.save(todo);	
	        // indexにリダイレクト	
	        return "redirect:/";	
	    }	
	    	
	    @GetMapping("/{id}")	
	    // パスパラメータを受け取るアノテーション	
	    public ModelAndView edit (@PathVariable Long id) {	
	        ModelAndView mav = new ModelAndView();	
	        	
	        mav.addObject("todo", repository.findById(id));	
	        	
	        mav.setViewName("edit");	
	        	
	        return mav;	
	    }	
	    	
	    //　わかりやすくstoreメソッドと分けていますが、一緒でも動作します。   	
	    @PostMapping("/{id}")	
+	    // フォームのデータ検証結果を保持するオブジェクト	
-	    public String update (Todo todo) {	
+	    public String update (@Validated Todo todo, BindingResult result) { 	
+	        if (result.hasErrors()) {	
+	            return "edit";	
+	        }	
+	        	
	        repository.save(todo);	
	        	
	        return "redirect:/";	
	    }	
	    	
	    	
	    @PostMapping("/delete/{id}")	
	    // パスパラメータを受け取るアノテーション	
	    public String delete (@PathVariable Long id) {	
	        	
	        repository.deleteById(id);	
	        	
	        return "redirect:/";	
	    }	
	    	
	}	
		

```

<br>

```diff_java:/demo/src/main/java/com/example/demo/Todo.java
	package com.example.demo;	
		
	import jakarta.persistence.Column;	
	import jakarta.persistence.Entity;	
	import jakarta.persistence.GeneratedValue;	
	import jakarta.persistence.GenerationType;	
	import jakarta.persistence.Id;	
	import jakarta.persistence.Table;	
	import jakarta.validation.constraints.NotBlank;	
	import jakarta.validation.constraints.Size;	
		
	@Entity // エンティティを示すクラスに付けるアノテーション	
	@Table(name = "\"todos\"") // テーブルを指定するアノテーション	
	public class Todo {	
	    	
	    @Id // エンティティクラスのフィールドをデータベースのプライマリーキー	
	    @GeneratedValue(strategy = GenerationType.IDENTITY) // 自動でIDを生成	
	    private Long id;	
	    	
	    @Column // DBカラムマッピング	
+	    @NotBlank	
+	    @Size(min=1, max=10)	
	    private String title;	
	    	
	    @Column // DBカラムマッピング	
+	    @NotBlank	
+	    @Size(min=1, max=30)	
	    private String memo;	
	    	
	    /*	
	     * getter・setter	
	     * getter : フィールドの値を取り出す	
	     * setter　： フィールドに値を設定する	
	     */	
	    	
	    public Long getId() {	
	        return id;	
	    }	
		
	    public void setId(Long id) {	
	        this.id = id;	
	    }	
		
	    public String getTitle() {	
	        return title;	
	    }	
		
	    public void setTitle(String title) {	
	        this.title = title;	
	    }	
		
	    public String getMemo() {	
	        return memo;	
	    }	
		
	    public void setMemo(String memo) {	
	        this.memo = memo;	
	    }	
		
	}	
```

<br>

```diff_html:/demo/src/main/resources/templates/index.html
	<!DOCTYPE html>		
	<html lang="ja">		
	<head>		
	    <meta charset="UTF-8">		
	    <meta name="viewport" content="width=device-width, initial-scale=1.0">		
	    <title>一覧画面</title>		
	    <link th:href="@{/css/style.css}" rel="stylesheet">		
	</head>		
	<body>		
	    <div class="container">		
	        <h2>一覧画面</h2>		
-	        <form method="post" action="/">		
+	        <form method="post" action="/" th:object="${todo}">		
	            <input type="hidden" th:field="*{id}">		
	            <input type="text" placeholder="タイトルを入力..." th:field="*{title}">		
	            <br>		
+	            <div class="text-error" th:if="${#fields.hasErrors('title')}" 		
+	                th:errors="*{title}"  style="color:red"></div>		
	            <br>		
	            <textarea rows="4" placeholder="メモを入力..." th:field="*{memo}"/>	
	            <br>		
+	            <div class="text-error" th:if="${#fields.hasErrors('memo')}" 		
+	                th:errors="*{memo}"  style="color:red"></div>		
	            <br>		
	            <button type="submit">追加</button>		
	        </form>		
	        <table>		
	            <thead>		
	                <tr>		
	                    <th>#</th>		
	                    <th>タイトル</th>		
	                    <th>メモ</th>		
	                    <th></th>		
	                    <th></th>		
	                </tr>		
	            </thead>		
	            <tbody>		
	                <tr th:each="todo : ${todos}">		
	                    <td th:text="${todo.id}"></td>		
	                    <td th:text="${todo.title}"></td>		
	                    <td th:text="${todo.memo}"></td>		
	                    <td><a th:href="@{/} + ${todo.id}"><button>編集</button></a></td>		
	                    <td>		
	                        <form method="post" th:action="@{/delete/{id}(id=${todo.id})}">		
	                            <button type="submit">削除</button>		
	                        </form>		
	                    </td>		
	                </tr>		
	            </tbody>		
	        </table>		
	    </div>		
	</body>		
	</html>		
```

<br>

```diff_html:/demo/src/main/resources/templates/edit.html	
	<!DOCTYPE html>	
	<html lang="ja">	
	<head>	
	    <meta charset="UTF-8">	
	    <meta name="viewport" content="width=device-width, initial-scale=1.0">	
	    <title>編集画面</title>	
	    <link th:href="@{/css/style.css}" rel="stylesheet">	
	</head>	
	<body>	
	    <div class="container">	
	        <h2>編集画面</h2>	
	        <form method="post" th:action="@{/*{id}}" th:object="${todo}">	
+	            <input type="hidden" th:field="*{id}">	
	            <input type="text" placeholder="タイトルを入力..." th:field="*{title}">	
	            <br>	
+	            <div class="text-error" th:if="${#fields.hasErrors('title')}" 	
+	                th:errors="*{title}"  style="color:red"></div>	
	            <br>	
	            <textarea rows="4" placeholder="メモを入力..." th:field="*{memo}"></textarea>	
	            <br>	
+	            <div class="text-error" th:if="${#fields.hasErrors('memo')}" 	
+	                th:errors="*{memo}"  style="color:red"></div>	
	            <br>	
	            <button type="submit">編集</button>	
	        </form>	
	    </div>	
	</body>	
	</html>	

```
アプリケーションを実行します。

http://localhost:8080/

動作確認して終了です。

ここまでの内容で簡単なアプリケーションは作成できるようになります。