Spring Bootでデータを保存する-その2（更新と削除）

# 背景・目的
[Spring Bootでデータを保存する-その1](https://qiita.com/zumax/items/2e387254c736659bf20c)では、H2データベースを使用して、データの登録を試しました。
今回は、保存されたデータの更新や削除を試します。

# 実践
[Spring Boot 3 プログラミング入門](https://www.amazon.co.jp/Spring-Boot-3-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798069167
)の内容を参考に試してみます

## 前提
https://qiita.com/zumax/items/2e387254c736659bf20c#%E5%AE%9F%E8%B7%B5

環境構築やコードは、上記のページの状態から始めます

## データの初期化
1. コントローラークラスに下記を追記します
    ```
      @PostConstruct
      public void init() {
        Person p1 = new Person();
        p1.setFirstName("Ichiro");
        p1.setLastName("Suzuki");
        repository.saveAndFlush(p1);
    
        Person p2 = new Person();
        p2.setFirstName("Taro");
        p2.setLastName("Yamada");
        repository.saveAndFlush(p2);
    
        Person p3 = new Person();
        p3.setFirstName("Hanako");
        p3.setLastName("Yamada");
        repository.saveAndFlush(p3);
    
      }
    ```
    - `@PostConstruct`
        - コンストラクタ
        - インスタンスが生成された後に、最初に一度だけ呼び出される
1. ビルドと実行します
    ```
    $ mvn package
    $ java -jar target/rest-db-0.0.1-SNAPSHOT.jar
    ```
1. localhost:8080で、初期登録されているかを確認します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/82c4b6a0-bb3c-b293-3dd7-88ad04ff8779.png)

## 更新処理の追加
### テンプレートの追加
1. templates配下にedit.htmlを用意します
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/8a9acf5a-f4d2-dc0f-e836-c54944ccbd62.png)

1. 下記のコードを追加します
    ```
    <!DOCTYPE html>
    <html> 
    <head>
        <title>top page</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
    </head>
    <body class="container">
      <h1 class="display-4 mb-4" th:text="${title}"></h1>
      <p th:text="${message}"></p>
    
      <form method="post" action="/edit" th:object="${formModel}">
        <input type="hidden" name="id" th:value="*{id}" />
        <div class="mb-3">
          <label for="name" class="form-label">FirstName</label>
          <input type="text" class="form-control" name="firstName" th:value="*{firstName}" />
        </div>
        <div class="mb-3">
          <label for="name" class="form-label"></label>LastName</label>
          <input type="text" class="form-control" name="lastName" th:value="*{lastName}" />
        </div>
        <div class="mb-3">
          <input type="submit" class="btn btn-primary" value="Create" />
        </div>
      </form>
    
      <table class="table">
        <thread>
          <tr>
            <th>firstName</th>
            <th>lastName</th>
          </tr>
        </thread>
        <tbody>
          <tr th:each="person : ${people}">
            <td th:text="${person.firstName}"></td>
            <td th:text="${person.lastName}"></td>
          </tr>
        </tbody>
      </table>
    </body>
    </html>
    ```
1. 以前作成していたindex.htmlの変更点は下記のとおりです
    - actionを`/edit`に変更
    - hiddenを追加
    ```
    $ diff ./src/main/resources/templates/index.html ./src/main/resources/templates/edit.html 
    11c11,13
    <   <form method="post" action="/" th:object="${formModel}">
    ---
    > 
    >   <form method="post" action="/edit" th:object="${formModel}">
    >     <input type="hidden" name="id" th:value="*{id}" />
    $
    ```
### Repositoryにメソッドを追加
IDでエンティティを検索し、取り出す処理の追加
1. PersonRepositoryにメソッドを追加します
    ```
    public Optional<Person> findById (Long id);
    ```
    - Optional
        - Nullかもしれないオブジェクトをラップするクラス
        - findByIdにより、Personオブジェクトを取得するが、見つからない可能性があり、その場合はNullとなる
        - 見つからない場合は、必ずOptionalインスタンスが返される

### リクエストハンドラの作成
edit用のリクエストハンドラを作成します。
- GETアクセス用に、editメソッド
- POSTアクセス用に、updateメソッド

1. WebControllerクラスに下記のメソッドを追加します
    ```
      @RequestMapping(value = "/edit/{id}", method=RequestMethod.GET)
      public ModelAndView edit(@ModelAttribute Person person ,@PathVariable int id,ModelAndView mav) {
        mav.setViewName("edit");
        mav.addObject("title","edit page");
        Optional<Person> data = repository.findById((long)id);
        mav.addObject("formModel", data.get());
      
        return mav;
      }
    
      @RequestMapping(value = "/edit", method=RequestMethod.POST)
      @Transactional
      public ModelAndView update(@ModelAttribute Person person, ModelAndView mav) {
          repository.saveAndFlush(person);
          return new ModelAndView("redirect:/");
      }

    ```
1. ビルドとSpring Bootを実行します
    ```
    $ mvn package
    $ java -jar target/rest-db-0.0.1-SNAPSHOT.jar
    ```

### 動作確認
1. localhost:8080にアクセス。上記の通り、初期値が登録されている
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/7fe9a35e-72b0-259c-9162-bca02a75a484.png)

1. localost:8080/edit/1にアクセスすると、登録されているIchiro Suzukiが表示されます
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e23c50b6-6cea-1a2f-419d-c44fc8a598e5.png)

1. LastNameをSuzuki→Satoに変更し、Updateをクリックします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/306a4918-3ea1-afdd-773a-b8e17bf0cad4.png)

1. 登録されました
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/6cdb5a5e-0cff-2eb1-1e87-f512237c9862.png)

## 削除処理の追加
### テンプレートの作成
1. delete.htmlを追加します
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/b2dbc82a-6409-a2c2-ced1-afa1426122f4.png)

1. 下記のコードを追加します
    ```
    <!DOCTYPE html>
    <html> 
    <head>
        <title>top page</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css">
    </head>
    <body class="container">
      <h1 class="display-4 mb-4" th:text="${title}"></h1>
      <p th:text="${message}"></p>
    
      <form method="post" action="/delete" th:object="${formModel}">
        <input type="hidden" name="id" th:value="*{id}" />
        <div class="mb-3">
          <label for="name" class="form-label">FirstName</label>
          <input type="text" class="form-control" name="firstName" th:value="*{firstName}" />
        </div>
        <div class="mb-3">
          <label for="name" class="form-label"></label>LastName</label>
          <input type="text" class="form-control" name="lastName" th:value="*{lastName}" />
        </div>
        <input type="submit" class="btn btn-primary" value="Delete" />
      </form>
    </body>
    </html>
    ```
### リクエストハンドラの作成
1. 下記のメソッドを追加します
    ```
      @RequestMapping(value = "/delete/{id}", method=RequestMethod.GET)
      public ModelAndView delete(@PathVariable int id, ModelAndView mav) {
        mav.setViewName("delete");
        mav.addObject("title", "Delete Page");
        mav.addObject("message", "Are you sure you want to delete it?");
        Optional<Person> data = repository.findById((long)id);
        mav.addObject("formModel", data.get());
        return mav;
      }
    
      @RequestMapping(value = "/delete", method=RequestMethod.POST)
      @Transactional
      public ModelAndView remove(@RequestParam long id, ModelAndView mav) {
        repository.deleteById(id);
        return new ModelAndView("redirect:/");
      }
    ```
1. ビルドとSpring Bootを起動します
    ```
    $ mvn package
    $ java -jar target/rest-db-0.0.1-SNAPSHOT.jar
    ```

### 動作確認
1. localhost:8080にアクセス。上記の通り、初期値が登録されている
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/12337739-a136-ff9f-2e3c-c80858410eba.png)

1. localhost:8080/delete/1にアクセスします
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/f050efbd-ba67-73f8-7281-e50849a64c86.png)
1. Deleteをクリックします。消えたようです
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/9cb72452-a55e-969c-087f-9a11f6c1ab4f.png)

1. H2コンソールでも確認します。確かに消えています
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/7379cd2e-8afa-3c54-fb61-cbe7f90b1f74.png)


# 考察
今回は、更新と削除をSpring Boot JPAを使用して試してみました。引き続き理解を深めたいと思います。

# 参考
https://docs.spring.io/spring-boot/how-to/data-initialization.html

https://docs.spring.io/spring-boot/documentation.html

[Spring Boot 3 プログラミング入門](https://www.amazon.co.jp/Spring-Boot-3-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798069167
)