MyBatisお試し #5 データ更新

## Prev

https://qiita.com/yamashun38/items/0c31e41d021aeb126b32

## 概要
- 業務でMyBatisを使用することがあったので理解度向上のために自宅でも色々触ってみる
- 下記のような操作が可能なアプリを作成する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/d25c23c7-7d5d-0f52-ecf4-e9dcde43b561.png)

## ソースコード

https://github.com/yamashun38/MyBatis

## ユーザ情報変更
- 指定したIDに対応するユーザ情報を変更できるよう実装
- ユーザ検索や削除と同様、指定したIDに対応するユーザが存在しない場合はエラー画面を表示

### UserMapper.xml

```xml:UserMapper.xml
    <!-- 指定されたIDのユーザ情報を更新 -->
    <update id="update">
        UPDATE
            users
        SET
            username = #{username},
            age = #{age},
            address = #{address}
        WHERE
            id = #{id}
    </update>
```

- 指定したIDに対応するユーザ情報をEntityとして受け取り情報を更新

### UserMapper.java

```java:UserMapper.java
    /**
     * データを更新
     */
    void update(UserEntity userEntity);
```

- 引数としてEntityを受け取りSQLを実行する

### UserLogic.java

```java:UserLogic.java
    /**
     * updateメソッドを呼び出し
     */
    public void updateUser(UserDto userDto) {

        UserEntity userEntity = toEntity(userDto);
        userMapper.update(userEntity);
    }
```

- 引数として変更後の情報が格納されたDTOを受け取る
- DTOをEntityに変換した後、updateメソッドを呼び出して情報の更新を実施

### MybatisController.java

```java:MybatisController.java
    /**
     * 情報を変更するユーザ選択
     */
    @GetMapping("/userSelect")
    public String userSelect() {

        return "update/userSelect";
    }

    /**
     * 変更内容入力画面
     */
    @GetMapping("/userUpdate")
    public String update(@RequestParam("id") int id, Model model) {

        try {
            userDto.setId(id);
            userDto = userLogic.findUser(userDto);
            model.addAttribute("userDto", userDto);
        } catch (UserNotFoundException e) {
            model.addAttribute("errorMessage", e.getMessage());
            return "update/userUpdate";
        }
        return "update/userUpdate";
    }

    /**
     * ユーザ情報変更完了画面
     */
    @PostMapping("/updateComplete")
    public String updateComplete(@ModelAttribute UserDto userDto) {

        userLogic.updateUser(userDto);
        return "update/updateComplete";
    }
```

- [localhost:8080/userSelect](localhost:8080/userSelect)へアクセスすると、情報を変更したいユーザのIDを入力する画面へ遷移
- IDを入力すると[localhost:8080/userUpdate](localhost:8080/userUpdate)へ遷移するので、変更したい情報を入力
- updateメソッドではuserLogicクラスのfindUserメソッドを呼び出すことによって、渡されたIDに対応するユーザ情報をDTOに格納
- もしIDに対応するユーザが存在しない場合はこのタイミングでエラーが返される
- 入力した内容は[localhost:8080/updateComplete](localhost:8080/updateComplete)へDTOとして渡されるため、そのDTOを元に情報の更新を実施

### userSelect.html

```html:userSelect.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>ユーザ情報変更</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
    <div class="container mt-3">
        <h1>ユーザ選択</h1>
        <form th:action="@{/userUpdate}" method="get">
            <div class="mb-3">
                <label for="userId" class="form-label">ユーザID</label>
                <input type="number" class="form-control" id="userId" name="id" required>
            </div>
            <button type="submit" class="btn btn-primary">進む</button>
        </form>

        <a th:href="@{/main}" class="btn btn-secondary mt-3">メイン画面へ戻る</a>
    </div>
</body>

</html>
```

- `th:action`によって進むボタンを押下した際の遷移先を指定
- `method`によってメソッドを指定
- 今回は進むボタンを押下するとGETメソッドによってフォームに入力したIDを[localhost:8080/userUpdate](localhost:8080/userUpdate)へ渡すよう実装

### userUpdate.html

```html:userUpdate.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>ユーザ情報変更</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css">
    <link rel="stylesheet" th:href="@{/css/style.css}">
</head>

<body>
    <div class="container mt-3">
        <h1>ユーザ情報変更</h1>
        <!-- 指定したIDのユーザが存在しない場合 -->
        <div th:if="${errorMessage}">
            <p th:text="${errorMessage}">指定したユーザは存在しません。</p>
        </div>
        <!-- 指定したIDのユーザが存在する場合 -->
        <div th:if="${userDto}">
            <form th:action="@{/updateComplete}" th:object="${userDto}" method="post">
                <input type="hidden" th:field="*{id}">
                <div class="mb-3">
                    <label for="userName" class="form-label">ユーザ名</label>
                    <input type="text" class="form-control" id="userName" th:field="*{username}" required>
                </div>
                <div class="mb-3">
                    <label for="userAge" class="form-label">年齢</label>
                    <input type="text" class="form-control" id="userAge" th:field="*{age}" required>
                </div>
                <div class="mb-3">
                    <label for="userAddress" class="form-label">住所</label>
                    <input type="text" class="form-control" id="userAddress" th:field="*{address}" required>
                </div>
                <button type="submit" class="btn btn-primary">更新</button>
            </form>
        </div>
            <a th:href="@{/main}" class="btn btn-secondary mt-3">メイン画面へ戻る</a>
        </div>
</body>

</html>
```

- ユーザ検索や削除の際と同様、`th:if`によって条件分岐を実施
- 入力したIDに対応するユーザが存在する場合は、コントローラ側で該当IDの現在(変更前)のユーザ情報がセットされてビューに渡されるため、それぞれのフォームにユーザ情報をあらかじめ入力した状態で表示する
- コントローラに渡す情報について
    - 今回は情報を変更する際の抽出条件としてIDを使用するため、コントローラに渡すDTOにはIDも含める必要がある
(= POSTメソッドで渡すデータにIDも含める必要がある)
    - ただ、今回IDは変更不可としているためinputタグのtype属性の値として`hidden`を指定することで、画面には表示させずデータを渡すよう実装している

### updateComplete.html

```html:updateComplete.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>ユーザ情報変更</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css">
    <link rel="stylesheet" th:href="@{/css/style.css}">
</head>

<body>
    <div class="container mt-3">
        <h1>変更完了</h1>
        <p>ユーザ情報の変更が完了しました。</p>

        <a th:href="@{/allUsers}" class="btn btn-secondary mt-3">ユーザ一覧へ</a>
        <a th:href="@{/main}" class="btn btn-secondary mt-3">メイン画面へ戻る</a>
    </div>
</body>

</html>
```

- [localhost:8080/userUpdate](localhost:8080/userUpdate)にて更新ボタンを押下するとユーザ情報の更新が実施されるので、更新完了メッセージを表示する

### ユーザ情報変更
#### ユーザが存在する場合
- IDが`1`のユーザ情報を変更してみる

| 項目  | 現在 | 変更後 |
|:-|:-|:-|
| ユーザ名  | John  | John  |
| 年齢  | 18  | 20  |
| 住所  | Amerika  | Germany  |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/958e320e-3796-1f22-3482-59fcd3bb58e8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/9247c7da-b043-212c-8a59-c133a14769ef.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/e996d5fc-73b6-1fb2-b13b-fe7bdb2b2229.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/3455a6dc-9caa-563a-4209-4bc4191d546e.png)

#### ユーザが存在しない場合
- IDが`5`のユーザ情報を変更しようとする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/c7bbef3f-adc2-bafc-dc9e-6a69b3199c6d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/85ac43aa-5ee9-bcc3-6fdd-2ca04fd2bc72.png)