今話題のChatGPTにSpringBoot Webアプリを作ってもらった

## この記事の内容
最近は、YouTubeなどでもノンコーディングでWebサイトを作ってみた系の動画があるので、
おそらく、SpringBootでEntityが一個のWebアプリなら作れるだろうと思い、試してみた。

## ChatGPTとの会話
ちなみに、コードは一切手直ししていません。

### 最初の応答
こんな感じ。丁寧に依頼してみた。
![Screenshot 2023-03-03 at 12.00.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/31aafaf0-bf43-2176-5cf8-0bf4cd909363.png)


```java:Employee.java
package com.example.demo.model;

import javax.persistence.*;

@Entity
@Table(name = "employees")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "email")
    private String email;

    @Column(name = "phone")
    private String phone;

    // コンストラクタ、Getter、Setter、toStringの作成
    // ...
}
```
Employee Repositoryの作成
新しいパッケージを作成し、EmployeeRepositoryインターフェースを作成します。

```java:EmployeeRepository.java
package com.example.demo.repository;

import com.example.demo.model.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {

}
```

Employee Controllerの作成
新しいパッケージを作成し、EmployeeControllerクラスを作成します。

```java:EmployeeController.java
package com.example.demo.controller;

import com.example.demo.model.Employee;
import com.example.demo.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@Controller
public class EmployeeController {

    @Autowired
    private EmployeeRepository employeeRepository;

    @GetMapping("/")
    public String viewHomePage(Model model) {
        model.addAttribute("listEmployees", employeeRepository.findAll());
        return "index";
    }

    @GetMapping("/showNewEmployeeForm")
    public String showNewEmployeeForm(Model model) {
        Employee employee = new Employee();
        model.addAttribute("employee", employee);
        return "new_employee";
    }

    @PostMapping("/saveEmployee")
    public String saveEmployee(@ModelAttribute("employee") Employee employee) {
        employeeRepository.save(employee);
        return "redirect:/";
    }

    @GetMapping("/showFormForUpdate/{id}")
    public String showFormForUpdate(@PathVariable(value = "id") Long id, Model model) {
        Employee employee = employeeRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("Invalid employee Id:" + id));
        model.addAttribute("employee", employee);
        return "update_employee";
    }

    @GetMapping("/deleteEmployee/{id}")
    public String deleteEmployee(@PathVariable(value = "id") Long id) {
        Employee employee = employeeRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("Invalid employee Id:" + id));
        employeeRepository.delete(employee);
        return "redirect:/";
    }
}
```

Viewの作成は力尽きたようだ...

![Screenshot 2023-03-03 at 12.04.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/7c317292-2d9a-5fad-fff4-39435e3b4308.png)


### Viewの作成を再度依頼

こちらは、もう少し詳しく！とカジュアルに頼んだけど、AIは丁寧だ。
（人間だとブチギレる人もいるので、AIのほうがその点はいいかも）

![Screenshot 2023-03-03 at 12.05.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/47155098-a107-5821-621d-456d937cd3d1.png)

以下が、View（html）の作品群

```html:index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Employee Management System</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}" />
</head>
<body>
<div class="container">
    <h1 class="text-center">Employee Management System</h1>
    <br>
    <a href="/showNewEmployeeForm" class="btn btn-primary mb-3">Add New Employee</a>
    <br>
    <table class="table table-striped">
        <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
            <th>Phone</th>
            <th>Action</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="employee : ${listEmployees}">
            <td th:text="${employee.id}"></td>
            <td th:text="${employee.name}"></td>
            <td th:text="${employee.email}"></td>
            <td th:text="${employee.phone}"></td>
            <td>
                <a th:href="@{'/showFormForUpdate/' + ${employee.id}}" class="btn btn-sm btn-info mr-2">Edit</a>
                <a th:href="@{'/deleteEmployee/' + ${employee.id}}" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this employee?')">Delete</a>
            </td>
        </tr>
        </tbody>
    </table>
</div>
<script th:src="@{/js/bootstrap.min.js}"></script>
</body>
</html>
```

登録用のView
```html:new_employee.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>New Employee</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}" />
</head>
<body>
<div class="container">
    <h1 class="text-center">Add New Employee</h1>
    <br>
    <form th:action="@{/saveEmployee}" th:object="${employee}" method="post">
        <div class="form-group">
            <label for="name">Name:</label>
            <input type="text" th:field="*{name}" class="form-control" placeholder="Enter name" />
        </div>
        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" th:field="*{email}" class="form-control" placeholder="Enter email" />
        </div>
        <div class="form-group">
            <label for="phone">Phone:</label>
            <input type="text" th:field="*{phone}" class="form-control" placeholder="Enter phone number" />
        </div>
        <button type="submit" class="btn btn-primary">Save</button>
        <a href="/" class="btn btn-secondary ml-2">Cancel</a>
    </form>
</div>
<script th:src="@{/js/bootstrap.min.js}"></script>
</body>
</html>
```

### UpdateのViewが届いていないので催促してみた

![Screenshot 2023-03-03 at 12.08.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/b9e3f3be-dd1e-b698-3e46-a6794e8a90e5.png)

```html:update_employee.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Edit Employee</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}" />
</head>
<body>
<div class="container">
    <h1 class="text-center">Edit Employee</h1>
    <br>
    <form th:action="@{/updateEmployee}" th:object="${employee}" method="post">
        <input type="hidden" th:field="*{id}" />
        <div class="form-group">
            <label for="name">Name:</label>
            <input type="text" th:field="*{name}" class="form-control" placeholder="Enter name" />
        </div>
        <div class="form-group">
            <label for="email">Email:</label>
            <input type="email" th:field="*{email}" class="form-control" placeholder="Enter email" />
        </div>
        <div class="form-group">
            <label for="phone">Phone:</label>
            <input type="text" th:field="*{phone}" class="form-control" placeholder="Enter phone number" />
        </div>
        <button type="submit" class="btn btn-primary">Update</button>
        <a href="/" class="btn btn-secondary ml-2">Cancel</a>
    </form>
</div>
<script th:src="@{/js/bootstrap.min.js}"></script>
</body>
</html>

```

## 動作確認

動作確認してみた。
予想通りですが、（ある程度）ちゃんと動いた！
実はUpdateのところでSubmitすると404が返ってくるので、そこは後で、ChatGPTと相談した。

### まずは、動作の様子のスクショ

http://localhost:8080
にアクセスした状態。

Employee Management Systemという大仰なタイトルに身が引き締まる。

![Screenshot 2023-03-04 at 7.45.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/5a289dd7-cc0d-2fb2-5d40-52782c1f3e74.png)

データを入力しSaveしてみた。
![Screenshot 2023-03-04 at 7.47.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/f58195a7-b473-2431-4550-b58b90403616.png)

![Screenshot 2023-03-04 at 7.48.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/b214d38a-58ce-0641-1451-91eb1fc74255.png)


## 動作確認前の追加オーダー
実は、`application.properties`を依頼し忘れたので、以下のように追加依頼した。
前回の文脈は覚えていないはず？なので、文脈に依存しない依頼とした。

![Screenshot 2023-03-04 at 7.51.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/7ccd33d9-9efe-0642-0895-a0ae796c23c3.png)

これで（Updateを除いて）期待通りに動作した。

## H2のインメモリーモードのデータをH2コンソールから見る
H2はめったに使わないので、H2コンソールの使い方は毎回調べていた。
今回はChatGPTに気軽に聞いてみた。

![Screenshot 2023-03-04 at 7.54.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/00bbb7f8-a435-f979-02a1-8de3e673feac.png)

### H2のコンソールアクセス失敗したので記憶を頼りに追加依頼
上記の状態だとH2コンソールにアクセスすると404になるので、以下の追加依頼を実施！

![Screenshot 2023-03-04 at 7.56.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/f297bd93-29dd-771b-73cd-3b03e13c194c.png)

これで、H2コンソールも使えるようになった。
僕が「いかがでしょうか？」と聞いて、
ChatGPTが「おっしゃるとおりです」と返してきたときに、心が通じ合った気がした。

## Updateがエラーとなる問題をChatGPTに相談する。
まずは、問いかけ（なお、このときに、ViewとControllerはChatにベタっと貼り付けた。画像上は省略）
![Screenshot 2023-03-04 at 8.01.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/6dff2f57-19a8-78ee-e9cc-6c8010a77c40.png)

返ってきた回答がこちら。
![Screenshot 2023-03-04 at 8.03.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/ae6e47c2-02c9-a7d4-c6ba-2ecdbbab100d.png)

## Updateも動くようになった！
![Screenshot 2023-03-04 at 8.06.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/0fd78c26-0525-a2a2-67c8-2e78716f6db1.png)
![Screenshot 2023-03-04 at 8.07.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130262/434ab7d1-6bac-8b62-1286-96ac086156f7.png)

## 感想
周りでの利用例からすると、ChatGPTでSpringBootの超簡単なアプリなら作れるだろうと予測はしてた。
しかし、ちょっとぐらいは自分で考えて手直しする部分はあるだろうと思ってた。

結果としてコードは1行も自分で書いていない（コピペしただけ）ので、これは相当に頼れる相棒感満載だー！

少し真面目な話をすると、テストコードやテストデータの作成などに実際に適用し始めている例も身近にあるので、うまく使っていって良いサービスを作るのに役立てたい！


## 免責事項
（このセクションだけですます調で）

この作業の進め方は所属組織の標準的なものではありません。（少なくとも現時点では）
単なる個人的な実験です。

バリデーションとかダブルサブミット防止とか実用的なアプリケーションにするためのナレッジについては、別途、所属組織が開設している技術サイトがありますので、そちらを参照ください。