MyBatisお試し #3 新規登録

### Prev

https://qiita.com/yamashun38/items/7731d5ca3da41250fc31

## 概要
- 業務で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

## ユーザ新規登録
- フォームに入力した情報をDBに登録しユーザ一覧取得を行った際に表示されるよう実装
- IDは自動採番のため入力する項目は名前、年齢、住所の3項目とする

### UserMapper.xml

```xml:UserMapper.xml
    <!-- 入力された情報を受け取りデータを登録 -->
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO users(
            username,
            age,
            address
        )
        VALUES(
            #{username},
            #{age},
            #{address}
        )
    </insert>
```

- `username`、`age`、`address`を受け取りDBにINSERTする
- `useGeneratedKey`をtrueにすることで自動採番を有効化
- 採番先は`keyProperty`で指定したフィールドになる

### UserMapper.java

```java:UserMapper.java
    /**
     * データを登録
     */
    void insert(UserEntity userEntity);
```

### UserLogic.java

```java:UserLogic.java
    /**
     * insertメソッドを呼び出し
     * データを登録
     */
    public void insert(UserDto userDto) throws DuplicateKeyException {

        UserEntity userEntity = toEntity(userDto);
        userMapper.insert(userEntity);
    }

    /**
     * UserDtoからUserEntityに変換
     */
    public UserEntity toEntity(UserDto userDto) {

        UserEntity userEntity = new UserEntity();
        userEntity.setId(userDto.getId());
        userEntity.setUsername(userDto.getUsername());
        userEntity.setAge(userDto.getAge());
        userEntity.setAddress(userDto.getAddress());
        return userEntity;
    }
```

- insertメソッドでは入力情報として受け取った`userDto`を`userEntity`に変換しUserMapperインタフェースのinsertメソッドを呼び出す

### MybatisController.java

```java:MybatisController.java
    /**
     * ユーザ登録画面表示
     */
    @GetMapping("/userRegist")
    public String entry(Model model) {

        model.addAttribute("userDto", new UserDto());
        return "regist/userRegist";
    }

    /**
     * ユーザ登録完了画面表示
     */
    @PostMapping("/registComplete")
    public String regist(@ModelAttribute UserDto userDto) throws DuplicateKeyException {

        userLogic.insert(userDto);
        return "regist/registComplete";
    }
```

- [localhost:8080/userRegist](localhost:8080/userRegist)にアクセスすると新規ユーザ登録用の画面に遷移
- 入力する情報を`userDto`というオブジェクトとして持てるようentryメソッドのaddAttributeメソッド内でインスタンス化
- 登録ボタンを押下すると、入力した情報が`userDto`としてregistメソッドに渡される
    - 渡される際はPOSTメソッドで渡されるため、アノテーションは`@PostMapping`を使用
- モデル層のinsertメソッドを呼び出し入力したデータをDBに保存
- 保存後は[localhost:8080/registComplete](localhost:8080/registComplete)にて登録完了のメッセージを表示

### userRegist.html
- 登録情報入力画面

```html:userRegist.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>
        <form th:action="@{/registComplete}" th:object="${userDto}" method="post">
            <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>

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

</html>
```

- POSTメソッドを使用するため、formタグのmethod属性は`Post`を指定
- th:actionではボタンを押した際の遷移先を指定
- 今回は[localhost:8080/registComplete](localhost:8080/registComplete)に遷移するため`registComplete`を指定

### registComplete.html
- 登録完了画面

```html:registComplete.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>
```

### ユーザ登録
- IDが`5`のユーザを新規登録してみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/8a941465-b362-b3b8-f08e-496dd5fb00db.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/131bd2a0-aae6-aa0f-9e7e-4b67318f07bb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757184/f7080175-60cf-ff07-034e-e369fa755337.png)

## Next

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