SpringBoot + MySQLで作成したTodoリストに「完了」「未完了」ボタンを実装する！

# はじめに
SpringBoot + MySQLで作成したTodoリストアプリケーションに、Todoの状態を完了、未完了に切り替える機能を実装していく。（初学者なので備忘録）

ゴールは、**リストのtrue/falseを変更し、データベースを更新する**こと。

参考にさせていただいた記事では1度完了にしたTodoは未完了にはできなかったので、完了・未完了を切り替えられるように実装した。
参考にさせていただいた記事：https://qiita.com/morioheisei/items/52d722eeee919f3a1552

# 開発環境
```
OS:macOS Ventura 13.0.1
```
```
openjdk version "11.0.16" 2022-07-19 LTS
OpenJDK Runtime Environment (build 11.0.16+8-LTS)
OpenJDK 64-Bit Server VM (build 11.0.16+8-LTS, mixed mode)
```
```
mysql  Ver 14.14 Distrib 5.6.51, for osx10.17 (x86_64) using  EditLine wrapper
```
```
| todo  | CREATE TABLE `todo` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `title` varchar(30) NOT NULL COMMENT 'タイトル',
  `deadline` date NOT NULL COMMENT '期日',
  `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'ステータス',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '作成日時',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日時',
  PRIMARY KEY (`id`),
  UNIQUE KEY `title_unique` (`title`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='todoテーブル'                        |
```
# Todoリストにボタンを表示
index.html(トップページ）に表示されているTodoリストに、「完了にする」「未完了にする」ボタンを追加する。

`th:if="${todo.status}"`はstatusのblooeanがtrueの時、
`th:unless="${todo.status}"`はstatusのblooeanがfalseの時に表示するもの。

```html:index.html
<body>
■表示項目
    <table>
        <tr>
            <th>タイトル</th>
            <th>期日</th>
            <th>ステータス</th>
            <th>状態変更</th>
        </tr>
        <tr th:each="todo : ${todoList}" th:object="${todo}">
            <td th:text="*{title}"></td>
            <td th:text="${#temporals.format(todo.deadline, 'yyyy年MM月dd日')}"></td>
            <td>
                <span th:if="${todo.status}">完了</span>
                <span th:unless="${todo.status}">未完了</span>
            </td>
            <td>
                <form action="/toggle-status" method="patch">
                    <input type="hidden" name="id" th:value="${todo.id}"/>
                    <button type="submit" name="incomplete" th:if="${todo.status}">未完了にする</button>
                    <button type="submit" name="complete" th:unless="${todo.status}">完了にする</button>
                </form>
            </td>
        </tr>
    </table>
</body>
```
```html:index.html
<td>
    <form action="/toggle-status" method="get">
        <input type="hidden" name="id" th:value="${todo.id}"/>
        <button type="submit" name="incomplete" th:if="${todo.status}">未完了にする</button>
        <button type="submit" name="complete" th:unless="${todo.status}">完了にする</button>
    </form>
</td>
```
ここのボタンを押すと`/toggle-status`にリクエストが送られ、Controllerが処理が走る。
`th:value="${todo.id}"`でidを送信していて、statusを変更する該当のTodoリストの情報をControllerへ送っている。

# Controllerでidを受け取り、Serviceに送信
```java:TodoController
@GetMapping("/toggle-status")
    public String statusChange(Long id) {
        todoService.changeTodo(id);
        return "redirect:/";
    }
```
受け取ったidを`todoService.changeTodo`に送信。
直接Repositoryにidを送信してデータを取得しないのは、保守性を良くするため？です。

# Serviceでstatusを反転しデータを更新
```java:TodoService
public void changeTodo(Long id) {
    Todo todo = todoRepository.getById(id);
    Boolean todoStatus = todo.isStatus();
    Boolean changeStatus = !todoStatus;
    todo.setStatus(changeStatus);
    todoRepository.save(todo);
}
```
処理の流れとしては、
1. Controllerから渡ってきたidを使って、`todoRepository.getById(id);`で該当のデータを取得し、`Todo型のtodo`に代入
1. todoに`isStatus()`メソッドを使い、`Boolean型のtodoStatus`に代入
1. todoStatusのtrue/falseを反転させ`Blooean型のchangeStatus`に代入
1. todoに`setStatus()`メソッドでstatusのtrue/falseを反転
1. `todoRepository.save(todo)`でデータベースに保存

# 動作確認
![スクリーンショット 2022-12-10 2.14.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728891/0deb01f3-acfb-5857-1194-06c4470a15e6.png)
ステータス：未完了
状態変更：完了にする

![スクリーンショット 2022-12-10 2.14.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728891/6af5b51c-86d9-ca97-1fe2-eab132279375.png)
ステータス：完了
状態変更：未完了にする

実装できていますね。

# 最後に
Todoリストの完了・未完了を変更する機能を実装していきました。
次は編集機能を実装していきたいですね。