#23 Spring Mybatisを利用したデータベース操作[3. SELECT 複数件]

# #23 Spring Mybatisを利用したデータベース操作[3. SELECT 複数件]
今回はMybatisを用いてSELECT文を実装し、データを複数件取得します。

# 前提条件
この記事はSpringの最低限の知識が必要になります。
また、なるべく分かりやすく書くつもりですが、この記事の目的は自分の勉強のアウトプットであるため所々説明は省略します。

# 前回まで
前回はMybatisを利用してデータの挿入を行いました。

https://qiita.com/Jackoguro/items/f89993b68de898b1441c

# 構築環境
1. 各バージョン
Spring Boot ver 2.7.5
mybatis-spring-boot-starter ver 2.2.2
Model Mapper ver 3.1.0
jquery ver 3.6.1
bootstrap ver 5.2.2
webjars-locator ver 0.46
thymeleaf-layout-dialect ver 3.0.0

2. 依存関係
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/58b53ccd-7cf2-2d82-4214-9f0c08fced2e.png)

# 成果物
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884987/ea3e8896-9352-cea4-22bb-bf288c0038ae.png)



# 今回行うこと(手順)
今回は以下の流れに沿って進めていきます。
1. 事前準備
　1. application.propertiesに内容を追加
　2. UserMapper.javaにメソッドを定義
1. UserMapper.xmlにSELECT文を記述
1. サービスの実装
　1. UserService.java
　2. UserServiceImpl.java
1. コントローラ(UserListController.java) の修正
1. 画面(list.html)の修正

## 1. 事前準備
### 1. application.propertiesに内容を追加
```properties:application.properties
# DataSource
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.username=system 
spring.datasource.password=5931
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver

# Message
spring.messages.basename=messages/messages, validation/ValidationMessages

# MyBatis
mybatis.mapper-locations=classpath*:mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.type-aliases-package=com.example.model

# Log Level
logging.level.com.example=debug
```
<br>
 
追加部分
```properties
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.type-aliases-package=com.example.model
```

:::note
- mybatis.configuration.map-underscore-to-camel-case：このプロパティにtrueを設定すると、select結果のアンダースコアをキャメルケースに変換することができます。
例) select結果のカラム名がuser_idの場合、JavaクラスのuserIdとマッピングされる

- mybatis.type-aliases-package：``2. UserMapper.javaにメソッドを定義``で説明
:::

### 2. UserMapper.javaにメソッドを定義
```java:UserMapper.java
package com.example.repository;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.example.model.MUser;

@Mapper
public interface UserMapper {
	
	/* ユーザー登録 */
	public int insertOne(MUser user);
	
	/* ユーザー表示 */
	public List<MUser> findAllMUser();
}
```

```java
    /* テーブル(M_USER)から全データを取得する */
	public List<MUser> findAllMUser();
```

## 2. UserMapper.xmlにSELECT文を記述
```xml:UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<!-- Mapperとxmlのマッピング -->
<mapper namespace="com.example.repository.UserMapper">
	<!-- ユーザー1件登録 -->
	<insert id="insertOne">
		<!-- INSERT文は省略 -->
	</insert>
	
	<select id="findAll" resultType="MUser">
		SELECT * FROM M_USER
	</select>
</mapper>
```
```xml
    <!-- テーブル(M_USER)からデータを取得 -->
	<select id="findAll" resultType="MUser">
		SELECT * FROM M_USER
	</select>
```
SELECT文を記述するときは``<select>``タグを利用します。
``resultType``属性には戻り値のデータ型を指定します。今回の場合、取得する項目は複数件あるので``MUser``を指定していますが、項目が1つだけの場合、整数型(int)や文字列型(String)も戻り値として使用できます。

``1. 事前準備``の``2. UserMapper.javaにメソッドを定義``にて記述した以下の内容が役立ちます。
```properties:application.properties
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.type-aliases-package=com.example.model
```
1つ目の``mybatis.configuration.map-underscore-to-camel-case=true``に関しては先ほど説明したので割愛しますが、
2つ目の``mybatis.type-aliases-package=com.example.model``に関して、resultTypeにMUserなどのデータ型を指定する場合、パッケージ名まで含める必要がありますが、``mybatis.type-aliases-package``にエンティティクラス(``MUser.java``)までのパッケージを設定することで``UserMapper.xml``ではパッケージ名を省略することができます。

## 3. サービスの実装
### 1. UserService.java
まずは``UserService.java``に抽象メソッドを定義します。
```java:UserService.java
package com.example.service;

import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.springframework.web.multipart.MultipartFile;

import com.example.model.MUser;

public interface UserService {
	
	/* 性別のMapを生成する */
	public Map<String, Integer> getGenderMap(Locale locale);
	
	/* ユーザー登録 */
	public void signUp(MUser muser);
	
	/* ユーザー取得 */
	public List<MUser> getAllMUser();
}
```
```java
	/* テーブル(M_User)の全データを取得する */
	public List<MUser> getAllMUser();
```

### 2. UserServiceImpl.java
先ほど記述したメソッドを実装していきます
```java:UserServiceImpl.java
package com.example.service.impl;

// 省略

@Service
public class UserServiceImpl implements UserService {

	/* messages.propertiesのDIを注入 */
	@Autowired
	private MessageSource messagesource;
	
	/* レポジトリー(UserMapper.java)のDIを注入 */
	@Autowired
	private UserMapper mapper;
	
    // 省略
	
	/* データの挿入 */
	@Override
	public void signUp(MUser user) {
		mapper.insertOne(user);
	}

	/* ユーザー情報取得 */
	@Override
	public List<MUser> getAllMUser() {
		return mapper.findAllMUser();
	}
}
```
```java
	/* ユーザー情報取得 */
	@Override
	public List<MUser> getAllMUser() {
		return mapper.findAllMUser();
	}
```
メソッド内で先ほどSELECT文で作成した``findAllMUser();``を実装します。

## 4. コントローラ(UserListController.java) の修正
```java:UserListController.java
package com.example.controller;

// 省略

@Controller
@RequestMapping("/user")
public class UserListController {
	
	@Autowired
	private UserService userservice;
	
	@GetMapping("/list")
	public String getUserList(Model model) {
		
		// テーブル(M_USER)から全項目を取得
		List<MUser> userList = userservice.getAllMUser();
		
		// Modelに登録
		model.addAttribute("userList", userList);
		
        //list.htmlの呼び出し
		return "/user/list";
	}
}
```
``3. サービスの実装``の``2. UserServiceImpl.java``で実装した``getAllMUser()``を呼び出し、``model.addAttribute()``で取得した値を受け渡します。

## 5. 画面(list.html)の修正
最後に``UserListController.java``から取得した``userList``を用いて画面取得したデータを画面に表示させて行きます。
```html:list.html
<!DOCTYPE html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="~{layout/layout}">
<head>
<title>ユーザー一覧</title>
<!-- 個別CSS読込 -->
<link rel="stylesheet" th:href="@{/css/user/list.css}">
</head>
<body>
	<div layout:fragment="content">
		<div class="header border-bottom">
			<h1 class="h2">ユーザ一覧画面</h1>
		</div>
		<!-- 一覧表示 -->
		<div>
			<table class="table table-striped table-bordered table-hover table-primary">
				<thead class="thead-light">
					<tr>
						<th class="th-width">ユーザーID</th>
						<th class="th-width">電話番号</th>
						<th class="th-width">郵便番号</th>
						<th class="th-width">住所</th>
						<th class="th-width">ユーザー名</th>
						<th class="th-width">パスワード</th>
						<th class="th-width">誕生日</th>
						<th class="th-width">年齢</th>
						<th class="th-width">性別</th>
						<th class="th-width">詳細</th>
					</tr>
				</thead>
				<tbody>
					<tr class="align-middle" th:each="item : ${userList}">
						<td th:text="${item.userId}"></td>
						<td th:text="${item.phoneNumber}"></td>	
						<td th:text="${item.postalNumber1} == null ? '登録されていません' : |${item.postalNumber1} - ${item.postalNumber2}|"></td>
						<td th:text="${item.address} == null ? '登録されていません' : ${item.address}"></td>
						<td th:text="${item.userName}"></td>
						<td th:text="${item.password}"></td>
						<td th:text="${item.birthday2} == null ? '登録されていません' : ${#dates.format(item.birthday2, 'YYYY/MM/dd')}"></td>
						<td th:text="${item.age} == null ? '登録されていません' : ${item.age}"></td>
						<div th:switch="${item.gender}">
							<td th:case= 0 th:text='男性'></td>
							<td th:case= 1 th:text='女性'></td>
							<td th:case= "*" th:text='登録されていません'></td>
						</div>
						<td>
							<a class="btn btn-primary" th:href="@{'/user/detail/' + ${item.userId}}">
								詳細
							</a>
						</td>
					</tr>
				</tbody>
			</table>
		</div>
	</div>
</body>
</html>
```

# 最後に
Mybatisを用いたSELECT文による画面表示は以上になります。

今回はデータの表示に``<table></table>``を用いましたが、その際にBootstarpの``Tables``の機能を使用しました。
今回使用した機能に加え、他の関連する機能を以下の記事にまとめました。

https://qiita.com/Jackoguro/items/b35fce44c0e60d8240e1