Springboot＋Tymeleaf+Mybatis+MySQLでのCRUD処理実装（基本）

学習のためのCRUDの基本実装をしました。備忘録としてまとめました。
画面上にHelloWorld実装まではできるものとして書いてます。
MySQLにはあらかじめテーブルを用意しています。

## 開発環境

- eclipse IDE
- Java 11
- maven
- Tymeleaf
- Mybatis
- MySQL

## 設定ファイルの編集

**application.propertiesにmySqlとの接続情報を記述**

```java
spring.datasource.url = jdbc:mysql://localhost/データベース名?serverTimezone=Asia/Tokyo
spring.datasource.username = root
spring.datasource.password = データベースのパスワード
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.mvc.hiddenmethod.filter.enabled: true
```


**Pom.xmlへの依存関係の記述（プロジェクト生成時依存関係セットに足りないものを追加）**

```java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>SymphogearTest</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>SymphogearTest</name>
	<description>project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.2.0</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>ture</optional>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
```

##　実装コード

###コントローラークラス（画面操作と処理の実行をつなぐクラス）

```java
package io.spring.gungnir.controller;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import io.spring.gungnir.dto.UserSearchRequest;
import io.spring.gungnir.entity.User;
import io.spring.gungnir.service.UserService;

@Controller　//コントローラークラスの宣言
public class UserController {
	
	@Autowired　//サービスクラスのnewを自動でしてくれるアノテーション
	UserService userService;
	
	/*
	 * URL（localhost:8080/user）でアクセスでトップ画面の表示
	 */
	@GetMapping(value = "/user")　//このURLにマッピングされておりGetするとメソッドが動く
	public String display() {
		return"top";　//top.htmlの画面を表示
	}
	

	/*
	 * 一件検索するためのフォームを表示
	 */
	@GetMapping(value = "/user/search")　//トップ画面でto search formを押下した時の画面遷移
	public String displaySearch() {
			return"player_search";　//player_search.htmlの画面を表示
	}
	

	/*
	 * 一件検索の実行
	 */
	@RequestMapping(value = "/user/id_search", method = RequestMethod.POST )　
　　//searchボタンを押され/user/id_searchが呼ばれたとき動く。フォームに入力されたIDをpostで受け取る
	
　public String search(@ModelAttribute UserSearchRequest userSearchRequest, Model model){  
　　//@ModelAttributeがpostされたリクエストをuserSearchReqesutに格納する（同時にnewする）
		
　　User user = userService.search(userSearchRequest);　//サービスクラスのメソッドにuserSerchReqestを引数として渡す
		model.addAttribute("user_info",user);　
　　　//サービスクラスメソッドの結果をuserに詰める。テンプレートで使うキーとして”user_info”を指定
		
　　return"player_search";　//player_search.htmlの画面を表示
	}
	

  /*
	 * 全件表示
	 */
	@PostMapping(value = "/user/list")　//player listボタンで/user/listが呼ばれたとき動く
	public String getUserList(Model model) {
		List <User> list = userService.searchAll();
		//リスト型でサービスクラスのインスタンスメソッドを呼び出す（リスト取得の指示だし）
		model.addAttribute("users_info", list);　//結果をlistに詰める。（users_infoがキー）
		return "list";	//list.htmlの画面を表示
	}
	

　/*新規プレイヤー登録画面を表示
	 * 画面遷移のみ
	 */
	@PostMapping(value = "/user/add")　//to sing up formのボタンで/user/addが呼ばれたとき動く
	public String displayAdd() {
		return "add_player";　//add_playerの画面を表示
	}
	
	
　/*登録の実行
	 * 登録情報の表示
	 */
	@RequestMapping(value = "user/add_comp", method = RequestMethod.POST )　
　　//sign upが押され/user/add_compが呼ばれた時動く。フォームの内容をpostで受け取る
	
　public String create(@ModelAttribute UserSearchRequest userAdd, Model model) {
		//postされたリクエストをusesrAddに格納+new
		
　　userService.create(userAdd);//追加処理の実行をサービスクラスに指示
		User user = userService.createCheck(userAdd);　//追加した情報をセレクトしとってくるよう指示
		model.addAttribute("user_add", user);　//セレクト結果をuserに詰める。（user_addをキー）
		return "add_comp";	//add_comp.htmlの画面を表示	
	}
	
	
　/*
	 * 編集画面への遷移
	 */
	@PutMapping(value = "/user/conf/id={id}")　//updateが押されたとき動く
	public String editSelect(@PathVariable("id")String id ,Model model){
　　//@PathVariableでURL内のidを引数に取得

		User user = userService.editSelect(id);　//取得したidを渡してセレクト指示
		model.addAttribute("user_select",user);　//セレクト結果をuserに詰める。（user_selectがキー）
		return "conf_player";　//conf_player.htmlを表示
 }
　

　/*
　 *編集の実行
　 */
	@RequestMapping(value = "/user/edit/id={id}", method = RequestMethod.POST)　//editボタンが押されたとき動く
	public String update(@ModelAttribute UserSearchRequest edit) {
		userService.update(edit);　//postされたリクエストが格納されたeditを引数にupdateメソッド呼び出し
		
		return "edit";　//edit.htmlを表示	
	}
	
	
　/*削除の実行
	 * 
	 */
	@DeleteMapping(value = "user/delete/id={id}")　//deleteボタンが押されたとき動く
	public String displayDelete(@ModelAttribute UserSearchRequest delete) {
		userService.deleteOne(delete); postされたリクエストが格納されたdeleteを引数にdeleteOneメソッド呼び出し
		return "delete";　//delete.htmlを表示
	}
}
``######サービスクラス（画面からのリクエストを実行するクラス）

```java
package io.spring.gungnir.service;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import io.spring.gungnir.dto.UserSearchRequest;
import io.spring.gungnir.entity.User;
import io.spring.gungnir.repository.UserMapper;

@Service　//サービスクラスの宣言
public class UserService {
	
	@Autowired　//userMapperを自動でnewしてくれる
	private UserMapper userMapper;
	
　
  /*
　 * 一件検索表示
   */
  public User search(UserSearchRequest userSearchRequest) {
		return userMapper.search(userSearchRequest);　//検索結果をリターンで受け取る
	}
	

　/*
	 * 全件表示
	 */
	public List<User> searchAll(){
		return userMapper.searchAll();　//全件のリストをリターンで受け取る
	}
	

	/*
	 * 新規追加処理
	 */
	public void create(UserSearchRequest userAdd) {
		userMapper.create(userAdd);
	}
	

　/*
	 * 追加情報を画面表示
	 */
	public User createCheck(UserSearchRequest userAdd) {
		return userMapper.createCheck(userAdd);
	}
	
　
　/*
   *　編集対象の検索
   */
	public User editSelect(String id) {
		return userMapper.editSelect(id);
	}
	

　/*
   *　編集実行
   */
	public void update(UserSearchRequest edit) {
		userMapper.edit(edit);	
	}
	

　/*
	 * レコード情報削除
	 */
	public void deleteOne(UserSearchRequest delete) {
		userMapper.deleteOne(delete);
	}

}
```

###マッパークラス（データベースを操作するクラス）

```java
package io.spring.gungnir.repository;

import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import io.spring.gungnir.dto.UserSearchRequest;
import io.spring.gungnir.entity.User;

@Mapper //マッパークラスの宣言
public interface UserMapper {

	/*
	 * プレイヤー情報検索
	 */
	@Select("SELECT * FROM symphogear_players WHERE id = #{id}")
	User search(UserSearchRequest user);

	
	/*
	 * 全件表示
	 */
	@Select("SELECT * FROM symphogear_players")
	List<User> searchAll();
	
	
	/*
	 * 新プレイヤー情報登録 
	 */
	
	@Insert("INSERT INTO symphogear_players(id,name,symphogear_name)"
			+ "VALUES (#{id},#{name},#{symphogear_name})")
	void create(UserSearchRequest userAdd);
	
	
	/*
	 * 新追加情報表示
	 */
	@Select("SELECT * FROM symphogear_players WHERE id = #{id}")
	User createCheck(UserSearchRequest userAdd);
	
	
	/*
	 * 編集用の情報セレクト
	 */
	@Select("SELECT * FROM symphogear_players WHERE id = #{id}")
	User editSelect(String id);
	
	
	/*
	 * 情報編集 
	 */
	@Update("UPDATE symphogear_players "
			+ "SET name = #{name}, symphogear_name = #{symphogear_name} "
			+ "WHERE id = #{id}")
	void edit(UserSearchRequest edit);	

	
	/*
	 * レコード削除
	 */
	@Delete("DELETE FROM symphogear_players WHERE id = #{id}")
	void deleteOne(UserSearchRequest delete);
	
}
```

###DTOクラス（画面からのリクエストデータを格納するクラス）

```java
package io.spring.gungnir.dto;

import java.io.Serializable;

import lombok.Data;

	@Data //セッター、ゲッターを記述しなくても使用できるようになる
	public class UserSearchRequest implements Serializable{
		
		private String id;
		private String name;
		private String symphogear_name;
	}
```

###エンティティクラス（データベースから取得したデータを格納するクラス）

```java
package io.spring.gungnir.entity;

import lombok.Data;

@Data
public class User {

	/*
	 * ユーザー情報 entity
	 */
	private String id;
	private String name;
	private String symphogear_name;

}
```
以上
長くなったので
画面周りのhtmlは次の記事→https://qiita.com/dende-h/items/9501d07c0e4088a0018c

**感想・気づいたこと**

- 一通りまとめたことで、処理の流れがつかめた。
- 途中で、実際には不要なコードがわかりより簡潔なコードにできた。
- ここから入力チェックや例外処理など機能を増やしていく。