【Java】Spring JDBCで登録機能の実装

今回はJava SpringFWを用いて登録・更新・削除機能を実装してみました。
バリデーションについては、JPAではなくJDBCtemplateを使用しております。
以下はそれぞれに分けて解説をしておりますので、よければ参考にしてください！！


•　【更新】[Spring JDBCで更新機能の実装]()（作成中)
•　【削除】[Spring JDBCで削除機能の実装]()（作成中）
•　【まとめ】[Spring JDBCで登録・更新・削除]()（作成中）
•　【エラー解消】[Spring JDBCでエラーメッセージが消えない！？]()（作成中）

<h1>0,　目次</h1>
1,　完成品
2,　環境
3,　関連ソースコード　　
　　①　Form と entity
　　②　Controller
　　③　Service
　　④　Impl と Custom と Repository
　　⑤　HTML と JavaScript
　　⑥　messages.properties と ValidationMessages.properties
　　⑦　pom.xml

4,　参考にしたサイト

<h1>1,　完成品</h1>
<h4>ユーザー登録までの流れ</h4>
本記事では、A5SQLを用いてDBにユーザーを登録していきます。
HTMLではリストを使って初期値としてユーザーを表示させています。
そのため、事前にテストデータとしてEmployeesテーブルを作成しました。
参考までに：[【SQL】テーブルとレコード(登録処理用)](https://qiita.com/nakasan773/items/598c15046e86e70dac47)
ユーザーの登録や更新もこちらのテーブルを使っていきます！

![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178769/92640952-5611-2201-7bd7-799e8a7b6308.gif)
![画像6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178769/f252350c-bb17-d1dc-75b8-4811b7f1edb4.png)

<h1>2,　環境</h1>
Windows10
sts-4.10.0.RELEASE
A5SQL Mk-2 Version2.16.1

<b>〜前提として〜</b>
・Spring boot(STS)が導入されていること
・SQLを用いたデータベースの簡単な知識（insert,updateなどのSQL文）
・デバックができること


<h1>3,　関連ソースコード　</h1>
<h3>① Form と entity</h3>

```java:EmployeesForm.java
package jp.co.nakasan.test.database.dbtest;

import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.stereotype.Component;
import lombok.Data;

@Data
@Component
public class EmployeesForm {
	
	/**
	 *  radio
	 */
	private String radio;

	/**
	 *  id
	 */
	private String id;
	
	/**
	 *  名前
	 */
	// nullまたは空文字でないことをチェック
	@NotBlank(message = "{notblank_check}")
	// 最小値・最大値を指定(@size,@maxだと常に判定される)
	@Length(min = 0, max = 100, message = "{length_check}")
	private String name;
	
	/**
	 *  年齢
	 */
	@NotBlank(message = "{notblank_check}")
	@Length(min = 0, max = 3, message = "{length_check_age}")
	private String age;
	
	/**
	 *  誕生日
	 */
	@NotBlank(message = "{notblank_check}")
	// 誕生日の正規表現を指定
	@Pattern(regexp = "([1-2]{1}[0-9]{3}/[0-1]{1}[0-9]{1}/[0-3]{1}[0-9]{1}|[1-2]{1}[0-9]{3}-[0-1]{1}[0-9]{1}-[0-3]{1}[0-9]{1})", message = "{pattern_check_birthday}")
	private String birthday;
	
	/**
	 *  メールアドレス
	 */
	@Length(min = 0, max = 100, message = "{length_check}")
	// メールの正規表現を指定
	@Email
	private String eMail;
	
	/**
	 *  住所
	 */
	@Length(min = 0, max = 100, message = "{length_check}")
	private String address;
	
	/**
	 *  グループ
	 */
	@Length(min = 0, max = 100, message = "{length_check}")
	private String groupId;
}
```

今回は、<b>BindingResultクラス</b>を使用するため、@NotBlankのようにバリデーションをかけています。
<b>message = "{notblank_check}"</b> はエラーメッセージの日本語化に対応させるため、名前をつけています。
（あとでpropertiesファイルに紐付けます。）
また、@DateTimeFormatというアノテーションも使えるらしいのですが、フィールドの型を<b>localDate(日付時刻型)</b>にする必要があるとのこと。。今回は大人しく自作の正規表現でパターン化しました😂

```java:Employees.java
package jp.co.nakasan.test.database.entity;

import java.io.Serializable;
import java.sql.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import com.sun.istack.NotNull;
import lombok.Data;

@SuppressWarnings("serial")
@Data                                               // ゲッターとセッターが不要になる
@Entity                                             // Entityクラスの宣言
@Table(name = "employees", schema = "データベース名")  // テーブルと紐づけ
public class Employees implements Serializable{ 
	
	/**
	 * 社員id
	 */
	@Id			// プライマリキー
	@Column(name = "id")	// データベース上のカラムとのマッピングを指定
	private Integer id;
	
	/**
	 * 名前
	 */
	@Column(name = "name")
	@NotNull
	private String name;
	
	/**
	 * 年齢
	 */
	@Column(name = "age")
	@NotNull
	private Integer age;
	
	/**
	 * 生年月日
	 */
	@Column(name = "birthday")
	@NotNull
	private Date birthday;
	
	/**
	 * e-mail
	 */
	@Column(name = "email")
	private String email;
	
	/**
	 * 住所
	 */
	@Column(name = "address")
	private String address;
	
	/**
	 * グループ
	 */
	@Column(name = "groupid")
	private String groupId;
}
```

Entityクラスではデータベースの使用するテーブルとを紐づけています。
物理名では<b>birthDay</b>になっているが、マッピングする<b>SpringPhysicalNamingStrategyクラス</b>ではクラス内のすべてを<b>小文字変換</b>しているので、大文字小文字を区別する必要があるようです。<b>groupId</b>も同様です。

<h3>② Controller</h3>

```java:EmployeesController.java
package jp.co.nakasan.test.practicebase.dbtest;

import org.springframework.beans.factory.annotation.Autowired;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(path = "/valiSpring")
public class EmployeesController {

	@Autowired
	private EmployeesForm form;
	
	@Autowired
	private EmployeesService service;
	
	/**
	 * 初期画面
	 * @param model // 画面表示
	 * @return
	 */
	@RequestMapping(path = "", method = RequestMethod.GET)
	public String index(Model model) {

		model.addAttribute("List", service.getSelectedJudges());
		model.addAttribute("employeesForm", form);

		return "practice/valiSpring";
	}
	
	/**
	 * データの表示
	 * @param EmployeesForm
	 * @param model         // 画面表示
	 * @param BindingResult // バリデーション
	 * @param　proc　          // Jsのクリックイベント"select"または"button"
	 * @return
	 */
	@RequestMapping(path = "{proc}", method = RequestMethod.POST) // (form, bindingresult, model)の順でないとエラー
	public String pushSend(@PathVariable String proc, @Validated EmployeesForm inputForm, BindingResult result, Model model)
	{
		// セレクトボックス押下時
		if (proc.equals("select")) {
			
			// ユーザー情報取得
			this.form = service.getSelectedInfoData(inputForm);
			model.addAttribute("employeesForm", this.form);
			
		// 送信ボタン押下時 "null"
		} else if (inputForm.getRadio() == null) {
			
			// 入力値の表示(BindingResult対策)
			this.form = service.keepForm(inputForm);
			// 選択チェックエラー
	        model.addAttribute("messageList", service.getSelectedNull());
	        model.addAttribute("employeesForm", this.form);
	        
	    // 送信ボタン押下時 "insert"
		} else if ((inputForm.getRadio().equals("insert")) && (!(result.hasErrors()))) {
			
			// ユーザー新規登録 & 入力チェックエラー
			model.addAttribute("messageList", service.getSelectedInsert(inputForm));
			
	    // 送信ボタン押下時 "update"
		} else if ((inputForm.getRadio().equals("update")) && (!(result.hasErrors()))) {

	    	    --省略--

	    // 送信ボタン押下時 "delete"
		} else if (inputForm.getRadio().equals("dalete")) {

	    	    --省略--
		}
		
		model.addAttribute("List", service.getSelectedJudges());
		
		return "practice/valiSpring";
	}
}
```

<b>path = "{proc}"</b>で<b>「select」</b>と<b>「button」</b>のどちらか一方のパラメータを受け取れるようにしています。
こうすることで、ユーザーが画面内の<b>どっちのボタンを押したのか</b>を判定できるようにしています。(jsファイルで定義)
更新、削除処理については別記事で紹介してますので、本記事では割愛させて頂きますっ。🙇‍♂️

<h3>③ Service</h3>

```java:EmployeesService.java
package jp.co.nakasan.test.practicebase.dbtest;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import jp.co.nakasan.test.database.entity.Employees;
import jp.co.nakasan.test.database.repository.EmployeesRepository;

@Service
// データベースのトランザクション制御
@Transactional
public class EmployeesService {
	
	@Autowired
	EmployeesRepository repository;
	
	/**
	 * 全ユーザー情報取得処理
	 * @param 
	 * @return employees // 全ユーザーのデータ(id,名前,年齢,誕生日)
	 */
	public List<Employees> getSelectedJudges() {
		
		// 全ユーザー情報取得用変数リスト
		List<Employees> employees = null;
		// 全ユーザー情報取得(id,名前のみ)
		employees = repository.findEmployees();
		
		return employees;
	}
	
	/**
	 * 入力値を初期化させない処理
	 * @param EmployeesForm
	 * @return form // 入力値をそのまま返す
	 */
	// バリデーションエラーメッセージの隔離メソッド
	public EmployeesForm keepForm(EmployeesForm inputForm) {
		
		// formの初期化(別formの生成)
		EmployeesForm form = new EmployeesForm();
		
		// 入力初期値の保存
		form.setRadio(inputForm.getRadio());
		form.setId("0");
		form.setName(inputForm.getName());
		form.setAge(inputForm.getAge());
		form.setBirthday(inputForm.getBirthday());
		form.setEMail(inputForm.getEMail());
		form.setAddress(inputForm.getAddress());
		form.setGroupId(inputForm.getGroupId());
		
		return form;
	}
	
	/**
	 * ユーザー情報取得処理(1件)
	 * @param EmployeesForm
	 * @return 
	 */
	public EmployeesForm getSelectedInfoData(EmployeesForm inputForm) {
		
		Employees employeesList = null;

		// formの初期化
		EmployeesForm form = new EmployeesForm();
		
		// 選択されたユーザーID
		String selectedId = inputForm.getId();
		
		// ユーザーを選択していない場合
		if (selectedId.equals("0")) {
			
			form.setId("0");
			form.setName("");
			form.setAge("");
			form.setBirthday("");
			form.setEMail("");
			form.setAddress("");
			form.setGroupId("");
			
		} else {
			
			// ユーザーidで情報取得
			employeesList = repository.findInfoData(selectedId);
			
			// フォーマットの指定
	        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
			// Date型をString型に変換
			String Birthday = sdf.format(employeesList.getBirthday());
			
			form.setRadio(inputForm.getRadio());
			form.setId(employeesList.getId().toString());
			// nullを許可する
			// toString()だとnullが入ってしまう
			form.setName(Objects.toString(employeesList.getName(), ""));
			form.setAge(Objects.toString(employeesList.getAge(), ""));
			form.setBirthday(Objects.toString(Birthday, ""));
			form.setEMail(Objects.toString(employeesList.getEmail(), ""));
			form.setAddress(Objects.toString(employeesList.getAddress(), ""));
			form.setGroupId(Objects.toString(employeesList.getGroupId(), ""));
		}
		
		return form;
	}
	
	/**
	 * ラジオボタン判定
	 * @param
	 * @return list // エラーメッセージリスト
	 */
	public List<String> getSelectedNull() {
		
		List<String> list = new ArrayList<>();

		list.add("新規登録、更新、削除のいずれかを選択してください。");
		
		return list;
	}
	
	/**
	 * ユーザー新規登録処理
	 * @param EmployeesForm
	 * @return list // エラー&登録結果の判定リスト
	 */
	public List<String> getSelectedInsert(EmployeesForm inputForm) {
		
		// insert用変数
		Employees employees = new Employees();
		
		// エラーメッセージ用リスト
		List<String> list = new ArrayList<>();
		
		// フォーマットを指定
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        // Date型の初期化
		Date formatDate = null;
		
		// yyyy/MM/ddにフォーマット変換
		String formDate = inputForm.getBirthday().replace('-', '/');
		
		try {
			
			// String型からDate型に変換
			formatDate = sdf.parse(formDate);
			
			// java.util.Dateは日付型のクラス
			// 日付型のクラスに変換
			java.util.Date d1 = formatDate;
			
			// java.sql.date は java.util.dateクラスのサブクラス
			// サブクラスに変換（時分秒ミリ秒まで保存可）
			java.sql.Date d3 = new java.sql.Date(d1.getTime());
			
			employees.setName(inputForm.getName());
			employees.setAge(Integer.parseInt(inputForm.getAge()));
			employees.setBirthday(d3);
			
			// 空文字じゃなかったら実行(空文字だったらnullとして登録)
			if (!(inputForm.getEMail() == "")) {
				employees.setEmail(inputForm.getEMail());
			}
			if (!(inputForm.getAddress() == "")) {
				employees.setAddress(inputForm.getAddress());
			}
			if (!(inputForm.getGroupId() == "")) {
				employees.setGroupId(inputForm.getGroupId());
			}
					
		    // ユーザー登録処理
			int rowNumber = repository.insertRecord(employees);
			
			// デフォルトで"false"を設定
			boolean result = false;
			
			if (rowNumber > 0) {
	            // insert成功
	            result = true;
	        }
				
	        // ユーザー登録結果の判定
	        if (result == true) {
	            list.add("新規登録完了");
	        }
		
		} catch(Exception e) {
			
			list.add("データベースに問題がありました。入力しなおしてください。(登録処理)");
		}
		return list;
	}

		--更新処理--

		--削除処理--
}
```

Serviceクラスでの主な処理は以下の通りです。

<b>「全ユーザー情報取得処理」</b>・・・セレクトボックスで各ユーザー選択時に使用
<b>「入力値を初期化させない処理」</b>・・・イベント時に入力値をそのままキープさせる
<b>「ユーザー情報取得処理(1件)」</b>・・・選択したユーザー(1件)のデータ全てを取得
<b>「ラジオボタン判定処理」</b>・・・エラーメッセージの作成
<b>「ユーザー新規登録処理」</b>・・・ユーザー登録処理

判定メッセージについては各メソッドごとにリストを生成し、出力しています。

<h3>④ Impl と Custom と Repository</h3>

```java:EmployeesRepository.java
package jp.co.nakasan.test.database.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import jp.co.nakasan.test.database.entity.Employees;
import jp.co.nakasan.test.database.repository.custom.EmployeesRepositoryCustom;

/**
 * カスタムインターフェイスとJpaRepositoryを継承(extends)したもの。
 * @author　　なかさん。
 *
 */
@Repository
public interface EmployeesRepository extends JpaRepository<Employees, Integer>, EmployeesRepositoryCustom {	
}

```

基本<b>JPAリポジトリ</b>という便利なものでDBからデータなどの情報を取得できるわけですが、今回使用している<b>JdbcTemplate</b>はJPAでは取得できないような状況にも対応できる(自分で好きにカスタムして取得できる)とのことで、つまりはJPAより自由度が高いということですね。時と場合により使い勝手が良さそうです。🤔

JdbcTemplateはのちにでてくる<b>Implクラス</b>に記述します。
そして、JPA以外は<b>カスタムインターフェースの継承が必要</b>です。
厳密には必要なわけではありませんが、<b>JDBCのメソッドを都度列挙しなくて済む</b>ようになるので必然かと。
Repositoryはそれらの<b>継承のためのファイル</b>です。
継承イメージとしては
<b>
Repositoryクラス > JpaRepositry
Repositoryクラス > Customクラス(インターフェース) > Implクラス < JdbcTemplate
</b>
みたいな感じです。

```java:EmployeesRepositoryCustom.java
package jp.co.nakasan.test.database.repository.custom;

import java.util.List;
import jp.co.nakasan.test.database.entity.Employees;

/**
 * implの継承
 * @author なかさん。
 *
 */

public interface EmployeesRepositoryCustom {

	/**
	 * @param　　
	 */
	public List<Employees> findEmployees();

	/**
	 * @param　　id
	 */
	public Employees findInfoData(String id);

	/**
	 * @param　　employees
	 */
	public int insertRecord(Employees employees);
}
```

カスタムクラスではimplクラスを継承します。
implで作成したメソッドをそのままコピペするだけで終了です。^^;
逆にカスタムに持ってこないと、せっかくimpl内で書いたメソッドがそのままの状態で放置プレイされてしまいます汗

```java:EmployeesRepositoryImpl.java
package jp.co.nakasan.test.database.impl;

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import jp.co.nakasan.test.database.entity.Employees;
import jp.co.nakasan.test.database.repository.custom.EmployeesRepositoryCustom;

/**
 * JDBCtemplateでレコード取得
 * @author　 なかさん。
 * 
 */
@Component
public class EmployeesRepositoryImpl implements EmployeesRepositoryCustom {
	
	@Autowired
	JdbcTemplate jdbc;
	
	/**
	 * レコードの取得（全ユーザーのid,名前のみ）
	 * @param 
	 * @return
	 */
	public List<Employees> findEmployees() {
		
		// 返却値 初期化
		List<Employees> resultRec = null;
		
		RowMapper<Employees> rowMapper = new BeanPropertyRowMapper<Employees>(Employees.class);

		// --------------------
		// クエリー生成
		// --------------------
		StringBuffer query = new StringBuffer();
		query.append("	SELECT");
		query.append("	      e.id,                        ");
		query.append("	      e.name　　                      ");
		query.append("	FROM");
		query.append("	    employees e	    ");
		
		// データベースからデータをリストで取得
		List<Employees> list = jdbc.query(query.toString(), rowMapper);
		
		resultRec = list;
		
		return resultRec;
	}
	
	/**
	 * レコードの取得（ユーザー1件のレコード全て）
	 * @param id
	 * @return
	 */
	public Employees findInfoData(String id) {
		
		// 返却値 初期化
		Employees resultRec = null;
		
		RowMapper<Employees> rowMapper = new BeanPropertyRowMapper<Employees>(Employees.class);

		// --------------------
		// クエリー生成
		// --------------------
		StringBuffer query = new StringBuffer();
		query.append("	SELECT");
		query.append("      e.id,          ");
		query.append("      e.name,        ");
		query.append("      e.age,         ");
		query.append("	    e.birthDay,    ");
		query.append("	    e.email,       ");
		query.append("	    e.address,     ");
		query.append("	    e.`groupId`    ");
		query.append("	FROM");
		query.append("	    employees e    ");
		query.append(" WHERE");
		query.append("		e.id = ?       ");

		// フォームのidとテーブルのidを紐づけるためリスト化
		ArrayList<String> paramList = new ArrayList<String>();
		paramList.add(id);
		
		// データベースからデータをリストで取得
		List<Employees> list = jdbc.query(query.toString(), rowMapper, paramList.toArray());
		
		resultRec = list.get(0);
		
		return resultRec;
	}
    
	/**
	 * ユーザー新規登録
	 * @param employees entityクラス
	 * @return
	 */
	public int insertRecord(Employees employees) { 
        
		// 返却値
		int query;
		
		// --------------------
		// クエリー生成
		// --------------------
		query = jdbc.update("INSERT INTO"
	               + " employees "
	               + "(name,"
	               + " age,"
	               + " birthDay,"
	               + " email,"
	               + " address,"
	               + " groupId)"
	               + " VALUES(?, ?, ?, ?, ?, ?)",
	               employees.getName(),
	               employees.getAge(),
	               employees.getBirthday(),
	               employees.getEmail(),
	               employees.getAddress(),
	               employees.getGroupId());
			
	        return query;
	}

	        --更新処理--

	        --削除処理--
}
```

Implクラスでの主な処理は以下の通りです。

<b>・　レコードの取得（全ユーザーのid,名前のみ）</b>
<b>・　レコードの取得（ユーザー1件のレコード全て）</b>
<b>・　ユーザー新規登録</b>

新規登録処理が<b>成功</b>すれば、返却値queryに<b>1</b>が
　　　　　　　<b>失敗</b>すれば、返却値queryに<b>0</b>が代入されます。
この値はServiceクラスでboolean型に変換され、処理結果メッセージの判定として使います。

<h3>⑤ HTML と JavaScript</h3>

```html:valiSpring.html

<body>
	<div class="contents">
		<form id="employeesForm" th:object="${employeesForm}" method="POST">
			<main class="ml-3 mt-3" th:fragment="init" role="main">
				IDは自動採番です。新規登録時，IDを選択しても反映されません。
				<br>
				再度「選択してください」を押すと入力値がクリアされます。
				<!--判定メッセージを出す-->
				<div class="0" style="color: green;">
					<tr th:each="name : ${messageList}">
						<br>
						<td th:text="${name}">
					</tr>
				</div>
				<!--エラーメッセージを出す-->
				<div class="0" style="color: brown;" th:if="${#fields.hasErrors('*')}">
					<tr th:each="err : ${#fields.errors('*')}">
						<br>
						<td th:text="${err}">
					</tr>
				</div>
				<!--登録用のラジオボタンを表示-->
				<p>
				<div class="1">
					<input type="radio" name="radio" th:value="insert" th:field="*{radio}">新規登録
					<input type="radio" name="radio" th:value="update" th:field="*{radio}">更新
					<input type="radio" name="radio" th:value="delete" th:field="*{radio}">削除
				</div>
				</p>
				<!--IDのセレクトボタン-->
				<div class="2">
					<select name="employeesId" th:field="*{id}" th:value="*{id}">
						<option value="0">--- 選択してください ---</option>
			        	<option th:each="list : ${List}" th:value="${list.id}" th:selected="${list.id == id}" th:inline="text">[[${list.id}]] : [[${list.name}]]</option>
			        </select>
				</div>
				<!--削除時以外の必須項目-->
				<div class="3 mt-3">
					<label style="width: 90">　名前 </label>
					<input style="width: 120" name="name"  th:field="*{name}" th:value="*{name}"/>
					
					<label style="width: 170">　年齢 </label>
					<input style="width: 120" name="age" th:field="*{age}" th:value="*{age}"/>
					
					<label style="width: 300">　生年月日 </label>
					<input style="width: 120" name="birthday"  th:field="*{birthday}" th:value="*{birthday}"/>
				</div>
				<!--項目-->
				<div class="4  mt-3">
					<label style="width: 90">　e-mail </label>
					<input style="width: 200" name="eMail"  th:field="*{eMail}" th:value="*{eMail}"/>
					
					<label style="width: 90">　住所 </label>
					<input style="width: 550" name="address"  th:field="*{address}" th:value="*{address}"/>
				</div>
				<!--項目-->
				<div class="5  mt-3">
					<label style="width: 90">　グループ </label>
					<input style="width: 70" name="groupId"  th:field="*{groupId}" th:value="*{groupId}"/>
					
					<button class="ml-4" name="send01" th:name="send">送信</button>
				</div>
			</main>
		</form>
	</div>
</body>
```

ここでもしBindingResultのバリデーションメッセージが表示されないとき、form名を疑ってください。
私が初めて実装したとき、form名はValiSpringFormで、エラーメッセージはformに「default　messages={0}は必須項目です。」と入っているのにうまく表示できませんでしたが、結論としてValiSpringForm → valiSpringFormと変更するとうまくいきました！(頭文字Vを小文字に変更)

原因は<b>BindingResultに入っているメッセージの中にform名</b>が書いてあり、それが<b>HTML側のform名と一致していなかったため</b>表示されなかったみたいです。
おそらくクラス内でバリデーションチェックを行う際、<b>頭文字が小文字へ強制的に変換</b>されてしまうのでしょう。
なので、私の時は<b>HTML,JavaScript,Controllerのform名</b>と<b>バリデーション結果のform名</b>を<b>一致させる</b>とうまく表示できるようになりました！ぜひ参考までに。🙇‍♂️

```javascript:Employees.js
var practice = (function() {

	var global = {
	}; // 名前空間オブジェクトを private オブジェクトで定義

	/**
	 * ページロード時に実行される処理。
	 */
	window.onload = function() {
		init();
	};

	function init() {
		
		// セレクトボタン押下時
		$('select[name="id"]').change(function() {
				// 現在アクセスしているパス情報を取得
				var rootPath = main.getDir(location, 0);
				
				// 遷移先への処理
				var form = $("#employeesForm");
				// "select"パラメータを渡す
				form.attr("action", rootPath + "/valiSpring/" + "select");
				form.attr("target", "_self");
				form.submit();
		});
		
		// 送信ボタン押下時
		$('button[name="send"]').click(function() {
				// 現在アクセスしているパス情報を取得
				var rootPath = main.getDir(location, 0);
				
				// 遷移先への処理
				var form = $("#employeesForm");
				// "buttom"パラメータを渡す
				form.attr("action", rootPath + "/valiSpring/" + "button");
				form.attr("target", "_self");
				form.submit();
		});
	}
	return global; // 名前空間オブジェクトを return する
})();
```

Controller側で<b>path="{proc}"</b>というようにパラメータを受け取る準備ができています。
あとは、selectやbuttonのように<b>任意のパラメータ</b>をコントローラに渡し、<b>イベントの処理分け</b>をするといった形です。

<h3>⑥ messages.properties と ValidationMessages.properties</h3>

```properties:messages.properties
--省略--

# フィールド名の日本語化
employeesForm.name = 名前
employeesForm.age = 年齢
employeesForm.birthday = 生年月日
employeesForm.eMail = メールアドレス
employeesForm.address = 住所
employeesForm.groupId = グループ名
```
ここでは<b>バリデーションの日本語化</b>をしています。
後でこちらのファイルを開くと
<b>employeesForm.name = \u540d\u524d　</b>
のように文字化けしてしまいますが、問題なく処理されますので気にしなくて大丈夫です！

```properties:ValidationMessages.properties
# 必須項目チェック
notblank_check = {0}は必須項目です。

# 字数制限チェック
length_check = {0}は100字以内で入力してください。
length_check_age = 年齢は3桁以内で入力してください。

# 正規表現チェック
pattern_check_birthday = 生年月日はyyyy/MM/ddまたはyyyy-MM-ddの形で入力してください。
pattern_check_eMail = メールアドレスを正しく入力してください。
```

Formで{messages=...}と名前をつけたものと先程の日本語化したフィールド名を紐づけるため、resorceフォルダ直下に「ValidationMessages.properties」という名前でプロパティファイルを作成します。

<h3>⑦ pom.xml</h3>
下記は参考までに。

```xml:pom.xml
<project>

--省略--
		
		<!-- validationライブラリ -->
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.2.4.Final</version>
		</dependency>
		<dependency>
		    <groupId>org.apache.tomcat.embed</groupId>
		    <artifactId>tomcat-embed-el</artifactId>
		    <scope>test</scope>
		</dependency>
		<dependency>
		  	<groupId>org.springframework.boot</groupId>
		  	<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>

--省略--

</project>
```

以上でユーザー登録処理の完了です🌟

他にもここでは解説しきれなかった更新・削除処理も執筆しておりますので、よければご覧ください！
また、なにか気になる点や間違っているとこなどがあれば遠慮なくご指摘ください...!!
まだまだ勉強中ですが、本記事が何かの参考になればとても幸いです。

<h1>4,　参考にしたサイト</h1>
•　 [【Java・SpringBoot】Spring JDBC でユーザー登録](https://qiita.com/suema0331/items/f07852225007570916c5)
•　 [SpringFrameworkでJdbcTemplateを使ってみる](https://tokkan.net/spring/jdbc.html)
•　 [Spring Bootのバリデーションメッセージの変更](https://qiita.com/tharao/items/ecc6a6a701c1f2ef199c)