CodeAGIを使って開発を行っていきます。（連載４回目）

## 【連載第4回】CodeAGIを活用したプログラムの自動生成

### プログラムの生成
設計書を指定し終えたら、いよいよプログラムを生成していきます。
画面左の「プログラム生成」ボタンからプログラム生成画面を表示します。
プログラム生成画面が表示されたら、「プログラム生成」ボタンを押します。

![screenshot.1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/66350580-3cb6-ab40-1b1b-9c57ac69b58d.jpeg)

生成が始まると、プログラム生成の状況をリアルタイムで表す画面に切り替わります。
プロジェクト情報設定画面で選択した言語、フレームワーク、パッケージに基づいたファイルの単位でプログラムが生成されます。
途中で生成を中断したい場合は「中止」ボタンをクリックすることで中断することができます。 

![screenshot.2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/81f9f73d-d5f4-19c4-afa4-8b3e373a54b1.jpeg)

生成が完了すると、以下のダイアログが表示されます。早速生成されたプログラムを確認してみましょう。

![screenshot.3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/36652252-ceb6-f485-e580-1ff9474a044f.jpeg)

![screenshot.4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/1a486e24-ae88-5197-cce7-7574b3290f4d.jpeg)

今回のプロジェクト設定の場合、大まかに以下の単位でプログラムが生成されていることがわかります。

**プロジェクト設定**
|  | フロントエンド | バックエンド |
|:-:|:-:|:-:|
| プログラミング言語 | Java | Java |
| フレームワーク | Spring Boot | Spring Boot |
| パッケージ | Thymeleaf <br> Bootstrap | Spring Data JPA <br> Lombok |

**生成されたプログラム**
- Entity.java
- SystemApplication.java
- Repository.java
- Service.java
- Form.java
- Controller.java
- action.js
- html

![screenshot.5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/ee4991f4-4df6-292c-6478-089a0f541a71.jpeg)

Entity.javaについて、どのようなプログラムが生成されたのか確認します。

![screenshot.6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/837dd8a6-40b9-eff5-514c-f38e8c2b3f9d.jpeg)

全部で5ファイル生成されていることがわかります。

<details>
<summary>MstItemCategory.java</summary>

```java
// MstItemCategory.java
package com.example.entity;

import lombok.Data;
import javax.persistence.*;
import java.util.Date;

// 商品種別マスタ
@Entity
@Table(name = "MST_ITEM_CATEGORY")
@Data
public class MstItemCategory {

    // 商品種別
    @Id
    @Column(name = "ITEM_CATEGORY", length = 3, nullable = false)
    private String itemCategory;

    // 商品種別名
    @Column(name = "ITEM_CATEGORY_NAME", length = 50)
    private String itemCategoryName;

    // 登録者
    @Column(name = "REGIST_PERSON", length = 5)
    private String registPerson;

    // 登録日時
    @Column(name = "REGIST_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date registDatetime;

    // 更新者
    @Column(name = "EDIT_PERSON", length = 5)
    private String editPerson;

    // 更新日時
    @Column(name = "EDIT_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date editDatetime;
}
```
</details>

<details>
<summary>MstItem.java</summary>

```java
// MstItem.java
package com.example.entity;

import lombok.Data;
import javax.persistence.*;
import java.util.Date;

/**
 * 商品マスタ
 */
@Entity
@Table(name = "MST_ITEM")
@Data
public class MstItem {

    /**
     * 商品コード
     */
    @Id
    @Column(name = "ITEM_CODE", length = 13, nullable = false)
    private String itemCode;

    /**
     * 商品名
     */
    @Column(name = "ITEM_NAME", length = 100)
    private String itemName;

    /**
     * 商品略称
     */
    @Column(name = "ITEM_SHORT_NAME", length = 50)
    private String itemShortName;

    /**
     * 商品種別
     */
    @Column(name = "ITEM_CATEGORY", length = 3)
    private String itemCategory;

    /**
     * 登録者
     */
    @Column(name = "REGIST_PERSON", length = 5)
    private String registPerson;

    /**
     * 登録日時
     */
    @Column(name = "REGIST_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date registDatetime;

    /**
     * 更新者
     */
    @Column(name = "EDIT_PERSON", length = 5)
    private String editPerson;

    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date editDatetime;
}
```
</details>

<details>
<summary>MstPerson.java</summary>

```java
// MstPerson.java
package com.example.entity;

import lombok.Data;
import javax.persistence.*;
import java.util.Date;

/**
 * 担当者マスタ
 */
@Entity
@Table(name = "MST_PERSON")
@Data
public class MstPerson {

    /**
     * 担当者コード
     */
    @Id
    @Column(name = "PERSON_CODE", length = 5, nullable = false)
    private String personCode;

    /**
     * 担当者名
     */
    @Column(name = "PERSON_NAME", length = 100)
    private String personName;

    /**
     * 担当者部署
     */
    @Column(name = "PERSON_DIVISION", length = 50)
    private String personDivision;

    /**
     * 担当者連絡先
     */
    @Column(name = "PERSON_PHON_NO", length = 15)
    private String personPhonNo;

    /**
     * 登録者
     */
    @Column(name = "REGIST_PERSON", length = 5)
    private String registPerson;

    /**
     * 登録日時
     */
    @Column(name = "REGIST_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date registDatetime;

    /**
     * 更新者
     */
    @Column(name = "EDIT_PERSON", length = 5)
    private String editPerson;

    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date editDatetime;
}
```
</details>

<details>
<summary>MstSupplier.java</summary>

```java
// MstSupplier.java
package com.example.entity;

import lombok.Data;
import javax.persistence.*;
import java.util.Date;

/**
 * 仕入先マスタ
 */
@Entity
@Table(name = "MST_SUPPLIER")
@Data
public class MstSupplier {

    /**
     * 仕入先コード
     */
    @Id
    @Column(name = "SUPPLIER_CODE", length = 4, nullable = false)
    private String supplierCode;

    /**
     * 仕入先名
     */
    @Column(name = "SUPPLIER_NAME", length = 100)
    private String supplierName;

    /**
     * 仕入先略称
     */
    @Column(name = "SUPPLIER_SHORT_NAME", length = 50)
    private String supplierShortName;

    /**
     * 仕入先連絡先
     */
    @Column(name = "SUPPLIER_PHONE_NO", length = 15)
    private String supplierPhoneNo;

    /**
     * 仕入先担当者
     */
    @Column(name = "SUPPLIER_PIC", length = 100)
    private String supplierPic;

    /**
     * 登録者
     */
    @Column(name = "REGIST_PERSON", length = 5)
    private String registPerson;

    /**
     * 登録日時
     */
    @Column(name = "REGIST_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date registDatetime;

    /**
     * 更新者
     */
    @Column(name = "EDIT_PERSON", length = 5)
    private String editPerson;

    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date editDatetime;
}
```
</details>

<details>
<summary>PurchaseInformation.java</summary>

```java
// PurchaseInformation.java
package com.example.entity;

import lombok.Data;
import javax.persistence.*;
import java.util.Date;

/**
 * 仕入情報エンティティクラス
 * テーブル名: 仕入情報
 */
@Entity
@Table(name = "PURCHASE_INFORMATION")
@Data
public class PurchaseInformation {

    /**
     * 仕入番号
     */
    @Id
    @Column(name = "PURCHASE_NO", nullable = false, length = 10)
    private Long purchaseNo;

    /**
     * 仕入日
     */
    @Column(name = "PURCHASE_DATE", nullable = false)
    @Temporal(TemporalType.DATE)
    private Date purchaseDate;

    /**
     * 仕入先コード
     */
    @Column(name = "SUPPLIER_CODE", nullable = false, length = 4)
    private String supplierCode;

    /**
     * 商品コード
     */
    @Column(name = "ITEM_CODE", nullable = false, length = 13)
    private String itemCode;

    /**
     * 仕入単価
     */
    @Column(name = "PURCHASE_UNIT_PRICE", nullable = false, length = 7)
    private Integer purchaseUnitPrice;

    /**
     * 仕入数量
     */
    @Column(name = "PURCHASE_QUANTITY", nullable = false, length = 5)
    private Integer purchaseQuantity;

    /**
     * 仕入担当者
     */
    @Column(name = "PURCHASE_PIC", nullable = false, length = 5)
    private String purchasePic;

    /**
     * 登録者
     */
    @Column(name = "REGIST_PERSON", length = 5)
    private String registPerson;

    /**
     * 登録日時
     */
    @Column(name = "REGIST_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date registDatetime;

    /**
     * 更新者
     */
    @Column(name = "EDIT_PERSON", length = 5)
    private String editPerson;

    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    @Temporal(TemporalType.TIMESTAMP)
    private Date editDatetime;
}
```
</details>

テーブル定義書の内容を反映したEntityが生成されているのが確認できます。
他のプログラムについても記載しておきます。

<details>
<summary>その他のプログラム</summary>

<details>
<summary>SystemApplication.java</summary>

```java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// Spring Bootアプリケーションのエントリーポイント
@SpringBootApplication
public class SystemApplication {

    // メインメソッド
    public static void main(String[] args) {
        SpringApplication.run(SystemApplication.class, args);
    }
}
```
</details>

<details>
<summary>MstItemCategoryRepository.java</summary>

```java
package com.example.repository;

import com.example.entity.MstItemCategory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * 商品種別マスタのリポジトリインターフェース
 */
@Repository
public interface MstItemCategoryRepository extends JpaRepository<MstItemCategory, String> {
}
```
</details>

<details>
<summary>MstItemRepository.java</summary>

```java
package com.example.repository;

import com.example.entity.MstItem;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * 商品マスタのリポジトリインターフェース
 */
@Repository
public interface MstItemRepository extends JpaRepository<MstItem, String> {
}
```
</details>

<details>
<summary>MstPersonRepository.java</summary>

```java
package com.example.repository;

import com.example.entity.MstPerson;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * 担当者マスタのリポジトリインターフェース
 */
@Repository
public interface MstPersonRepository extends JpaRepository<MstPerson, String> {
}
```
</details>

<details>
<summary>MstSupplierRepository.java</summary>

```java
package com.example.repository;

import com.example.entity.MstSupplier;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * 仕入先マスタのリポジトリインターフェース
 */
@Repository
public interface MstSupplierRepository extends JpaRepository<MstSupplier, String> {
}
```
</details>

<details>
<summary>PurchaseInformationRepository.java</summary>

```java
package com.example.repository;

import com.example.entity.PurchaseInformation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.Date;
import java.util.List;

/**
 * 仕入情報のリポジトリインターフェース
 */
@Repository
public interface PurchaseInformationRepository extends JpaRepository<PurchaseInformation, Long> {

    /**
     * 検索条件に基づいて仕入情報を取得するクエリ
     * 
     * @param supplierCode 仕入先コード
     * @param purchasePic 仕入担当者
     * @param startDate 仕入開始日
     * @param endDate 仕入終了日
     * @param itemCategory 商品種別
     * @param itemName 商品名
     * @return 仕入情報のリスト
     */
    @Query("SELECT pi FROM PurchaseInformation pi " +
           "JOIN MstSupplier ms ON pi.supplierCode = ms.supplierCode " +
           "JOIN MstPerson mp ON pi.purchasePic = mp.personCode " +
           "JOIN MstItem mi ON pi.itemCode = mi.itemCode " +
           "JOIN MstItemCategory mic ON mi.itemCategory = mic.itemCategory " +
           "WHERE (:supplierCode IS NULL OR pi.supplierCode = :supplierCode) " +
           "AND (:purchasePic IS NULL OR pi.purchasePic = :purchasePic) " +
           "AND (:startDate IS NULL OR pi.purchaseDate >= :startDate) " +
           "AND (:endDate IS NULL OR pi.purchaseDate <= :endDate) " +
           "AND (:itemCategory IS NULL OR mi.itemCategory = :itemCategory) " +
           "AND (:itemName IS NULL OR mi.itemName LIKE %:itemName%) " +
           "ORDER BY pi.supplierCode, pi.purchaseDate")
    List<PurchaseInformation> findByCriteria(
            @Param("supplierCode") String supplierCode,
            @Param("purchasePic") String purchasePic,
            @Param("startDate") Date startDate,
            @Param("endDate") Date endDate,
            @Param("itemCategory") String itemCategory,
            @Param("itemName") String itemName);
}
```
</details>

<details>
<summary>PurchaseInformationService.java</summary>

```java
package com.example.service;

import com.example.entity.PurchaseInformation;
import com.example.repository.PurchaseInformationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * 仕入情報サービスクラス
 */
@Service
public class PurchaseInformationService {

    @Autowired
    private PurchaseInformationRepository purchaseInformationRepository;

    /**
     * 検索条件に基づいて仕入情報を取得する
     *
     * @param supplierCode 仕入先コード
     * @param purchasePic 仕入担当者
     * @param startDate 仕入開始日
     * @param endDate 仕入終了日
     * @param itemCategory 商品種別
     * @param itemName 商品名
     * @return 仕入情報のリスト
     */
    public List<PurchaseInformation> searchPurchaseInformation(String supplierCode, String purchasePic, Date startDate, Date endDate, String itemCategory, String itemName) {
        return purchaseInformationRepository.findByCriteria(supplierCode, purchasePic, startDate, endDate, itemCategory, itemName);
    }
}
```
</details>

<details>
<summary>MstSupplierService.java</summary>

```java
package com.example.service;

import com.example.entity.MstSupplier;
import com.example.repository.MstSupplierRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 仕入先マスタサービスクラス
 */
@Service
public class MstSupplierService {

    @Autowired
    private MstSupplierRepository mstSupplierRepository;

    /**
     * すべての仕入先を取得する
     *
     * @return 仕入先のリスト
     */
    public List<MstSupplier> getAllSuppliers() {
        return mstSupplierRepository.findAll();
    }
}
```
</details>

<details>
<summary>MstPersonService.java</summary>

```java
package com.example.service;

import com.example.entity.MstPerson;
import com.example.repository.MstPersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 担当者マスタサービスクラス
 */
@Service
public class MstPersonService {

    @Autowired
    private MstPersonRepository mstPersonRepository;

    /**
     * すべての担当者を取得する
     *
     * @return 担当者のリスト
     */
    public List<MstPerson> getAllPersons() {
        return mstPersonRepository.findAll();
    }
}
```
</details>

<details>
<summary>MstItemCategoryService.java</summary>

```java
package com.example.service;

import com.example.entity.MstItemCategory;
import com.example.repository.MstItemCategoryRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 商品種別マスタサービスクラス
 */
@Service
public class MstItemCategoryService {

    @Autowired
    private MstItemCategoryRepository mstItemCategoryRepository;

    /**
     * すべての商品種別を取得する
     *
     * @return 商品種別のリスト
     */
    public List<MstItemCategory> getAllItemCategories() {
        return mstItemCategoryRepository.findAll();
    }
}
```
</details>

<details>
<summary>PurchaseInformationSearchForm.java</summary>

```java
package com.example.form;

import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.Size;
import java.util.Date;

/**
 * 仕入情報検索フォームクラス
 */
@Data
public class PurchaseInformationSearchForm {

    /**
     * 仕入先コード
     */
    private String supplierCode;

    /**
     * 仕入担当者
     */
    private String purchasePic;

    /**
     * 仕入開始日
     */
    @DateTimeFormat(pattern = "yyyy/MM/dd")
    private Date startDate;

    /**
     * 仕入終了日
     */
    @DateTimeFormat(pattern = "yyyy/MM/dd")
    private Date endDate;

    /**
     * 商品種別
     */
    private String itemCategory;

    /**
     * 商品名
     */
    @Size(max = 50, message = "商品名は最大50文字までです。")
    private String itemName;
}
```
</details>

<details>
<summary>PurchaseInformationController.java</summary>

```java
package com.example.controller;

import com.example.form.PurchaseInformationSearchForm;
import com.example.service.MstItemCategoryService;
import com.example.service.MstPersonService;
import com.example.service.MstSupplierService;
import com.example.service.PurchaseInformationService;
import com.example.entity.PurchaseInformation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.validation.Valid;
import java.util.List;

/**
 * 仕入情報コントローラークラス
 */
@Controller
@RequestMapping("/purchase")
public class PurchaseInformationController {

    @Autowired
    private PurchaseInformationService purchaseInformationService;

    @Autowired
    private MstSupplierService mstSupplierService;

    @Autowired
    private MstPersonService mstPersonService;

    @Autowired
    private MstItemCategoryService mstItemCategoryService;

    /**
     * 初期表示処理
     *
     * @param model モデル
     * @return 仕入情報照会画面
     */
    @GetMapping("/search")
    public String init(Model model) {
        // 仕入先リストを取得
        model.addAttribute("suppliers", mstSupplierService.getAllSuppliers());

        // 担当者リストを取得
        model.addAttribute("persons", mstPersonService.getAllPersons());

        // 商品種別リストを取得
        model.addAttribute("itemCategories", mstItemCategoryService.getAllItemCategories());

        // フォームの初期化
        PurchaseInformationSearchForm form = new PurchaseInformationSearchForm();
        model.addAttribute("searchForm", form);

        return "purchase/search";
    }

    /**
     * 検索処理
     *
     * @param form 検索フォーム
     * @param result バインディング結果
     * @param model モデル
     * @return 仕入情報照会画面
     */
    @PostMapping("/search")
    public String search(@Valid PurchaseInformationSearchForm form, BindingResult result, Model model) {
        if (result.hasErrors()) {
            return "purchase/search";
        }

        // 検索条件のバリデーション
        if (form.getStartDate() == null && form.getEndDate() == null) {
            result.reject("error.search", "検索条件を指定してください。");
            return "purchase/search";
        }

        if (form.getStartDate() != null && form.getEndDate() != null && form.getStartDate().after(form.getEndDate())) {
            result.reject("error.search", "仕入日の検索条件の指定に誤りがあります。");
            return "purchase/search";
        }

        // 検索処理
        List<PurchaseInformation> purchaseInformationList = purchaseInformationService.searchPurchaseInformation(
                form.getSupplierCode(),
                form.getPurchasePic(),
                form.getStartDate(),
                form.getEndDate(),
                form.getItemCategory(),
                form.getItemName()
        );

        if (purchaseInformationList.isEmpty()) {
            result.reject("error.search", "検索結果が存在しませんでした。");
            return "purchase/search";
        }

        // 検索結果をモデルに追加
        model.addAttribute("purchaseInformationList", purchaseInformationList);

        return "purchase/search";
    }
}
```
</details>

<details>
<summary>action.js</summary>

```java
// action.js

document.addEventListener("DOMContentLoaded", function() {
    // 初期表示時の処理
    initPage();

    // 検索ボタンのクリックイベント
    document.getElementById("searchButton").addEventListener("click", function() {
        // 検索処理を実行
        executeSearch();
    });
});

/**
 * 初期表示時の処理
 */
function initPage() {
    // 仕入開始日と仕入終了日の初期値を設定
    setInitialDates();
}

/**
 * 仕入開始日と仕入終了日の初期値を設定
 */
function setInitialDates() {
    const today = new Date();
    const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
    const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);

    document.getElementById("startDate").value = formatDate(firstDay);
    document.getElementById("endDate").value = formatDate(lastDay);
}

/**
 * 日付をyyyy/MM/dd形式にフォーマットする
 * @param {Date} date 日付オブジェクト
 * @returns {string} フォーマットされた日付文字列
 */
function formatDate(date) {
    const year = date.getFullYear();
    const month = ('0' + (date.getMonth() + 1)).slice(-2);
    const day = ('0' + date.getDate()).slice(-2);
    return `${year}/${month}/${day}`;
}

/**
 * 検索処理を実行
 */
function executeSearch() {
    // フォームのバリデーションを行い、エラーメッセージを表示する
    if (!validateForm()) {
        alert("検索条件を指定してください。");
        return;
    }

    // 検索条件に基づいてデータを取得し、結果を表示する
    // ここに検索処理の実装を追加
}

/**
 * フォームのバリデーションを行う
 * @returns {boolean} バリデーション結果
 */
function validateForm() {
    const startDate = document.getElementById("startDate").value;
    const endDate = document.getElementById("endDate").value;

    if (!startDate && !endDate) {
        return false;
    }

    if (new Date(startDate) > new Date(endDate)) {
        alert("仕入日の検索条件の指定に誤りがあります。");
        return false;
    }

    return true;
}
```
</details>

<details>
<summary>purchaseInformationSearch.html</summary>

```java
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>仕入情報照会</title>
    <link rel="stylesheet" href="/css/bootstrap.min.css">
    <script src="/js/action.js"></script>
</head>
<body>
<div class="container">
    <h1>仕入情報照会</h1>
    <form th:action="@{/purchase/search}" th:object="${searchForm}" method="post">
        <!-- エラーメッセージ表示 -->
        <div th:if="${#fields.hasErrors('*')}" class="alert alert-danger" role="alert">
            <p th:each="err : ${#fields.errors('*')}" th:text="${err}">エラーメッセージ</p>
        </div>

        <!-- 仕入先 -->
        <div class="form-group">
            <label for="supplierCode">仕入先：</label>
            <select id="supplierCode" name="supplierCode" class="form-control">
                <option value="">選択してください</option>
                <option th:each="supplier : ${suppliers}" th:value="${supplier.supplierCode}" th:text="${supplier.supplierShortName}"></option>
            </select>
        </div>

        <!-- 仕入担当者 -->
        <div class="form-group">
            <label for="purchasePic">仕入担当者：</label>
            <select id="purchasePic" name="purchasePic" class="form-control">
                <option value="">選択してください</option>
                <option th:each="person : ${persons}" th:value="${person.personCode}" th:text="${person.personName}"></option>
            </select>
        </div>

        <!-- 仕入日 -->
        <div class="form-group">
            <label for="startDate">仕入開始日：</label>
            <input type="date" id="startDate" name="startDate" class="form-control" th:value="${#dates.format(searchForm.startDate, 'yyyy-MM-dd')}">
        </div>
        <div class="form-group">
            <label for="endDate">仕入終了日：</label>
            <input type="date" id="endDate" name="endDate" class="form-control" th:value="${#dates.format(searchForm.endDate, 'yyyy-MM-dd')}">
        </div>

        <!-- 商品種別 -->
        <div class="form-group">
            <label for="itemCategory">商品種別：</label>
            <select id="itemCategory" name="itemCategory" class="form-control">
                <option value="">選択してください</option>
                <option th:each="category : ${itemCategories}" th:value="${category.itemCategory}" th:text="${category.itemCategoryName}"></option>
            </select>
        </div>

        <!-- 商品名 -->
        <div class="form-group">
            <label for="itemName">商品名：</label>
            <input type="text" id="itemName" name="itemName" class="form-control" th:value="${searchForm.itemName}" maxlength="50">
        </div>

        <!-- 検索ボタン -->
        <button type="submit" id="searchButton" class="btn btn-primary">検索</button>
    </form>

    <!-- 検索結果表示 -->
    <div th:if="${purchaseInformationList != null}">
        <h2>検索結果</h2>
        <table class="table table-bordered">
            <thead>
            <tr>
                <th>№</th>
                <th>商品コード</th>
                <th>商品名</th>
                <th>商品種別</th>
                <th>仕入先</th>
                <th>仕入日</th>
                <th>仕入単価</th>
                <th>仕入数量</th>
                <th>仕入金額</th>
                <th>仕入担当者名</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="info, iterStat : ${purchaseInformationList}">
                <td th:text="${iterStat.index + 1}">1</td>
                <td th:text="${info.itemCode}">商品コード</td>
                <td th:text="${info.itemName}">商品名</td>
                <td th:text="${info.itemCategory}">商品種別</td>
                <td th:text="${info.supplierName}">仕入先</td>
                <td th:text="${#dates.format(info.purchaseDate, 'yyyy/MM/dd')}">仕入日</td>
                <td th:text="${#numbers.formatInteger(info.purchaseUnitPrice, '###,###,##0')}">仕入単価</td>
                <td th:text="${#numbers.formatInteger(info.purchaseQuantity, '###,###,##0')}">仕入数量</td>
                <td th:text="${#numbers.formatInteger(info.purchaseUnitPrice * info.purchaseQuantity, '###,###,##0')}">仕入金額</td>
                <td th:text="${info.purchasePic}">仕入担当者名</td>
            </tr>
            </tbody>
        </table>
    </div>
</div>
</body>
</html>
```
</details>

<details>
<summary>Repository.java</summary>

```java
package com.example.repository;

import com.example.entity.MstSupplier;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * 仕入先マスタのリポジトリインターフェース
 */
@Repository
public interface MstSupplierRepository extends JpaRepository<MstSupplier, String> {
    // 仕入先コードを条件に仕入先情報を取得する
    MstSupplier findBySupplierCode(String supplierCode);
}
```
</details>

<details>
<summary>SupplierService.java</summary>

```java
package com.example.service;

import com.example.entity.MstSupplier;
import com.example.repository.MstSupplierRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 仕入先マスタのサービスクラス
 */
@Service
public class SupplierService {

    @Autowired
    private MstSupplierRepository mstSupplierRepository;

    /**
     * 仕入先コードを条件に仕入先情報を取得する
     * 
     * @param supplierCode 仕入先コード
     * @return 仕入先情報
     */
    public MstSupplier getSupplierByCode(String supplierCode) {
        return mstSupplierRepository.findBySupplierCode(supplierCode);
    }
}
```
</details>

<details>
<summary>SupplierForm.java</summary>

```java
package com.example.form;

import lombok.Data;

/**
 * 仕入先情報のフォームクラス
 */
@Data
public class SupplierForm {

    /**
     * 仕入先コード
     */
    private String supplierCode;

    /**
     * 仕入先名
     */
    private String supplierName;

    /**
     * 仕入先略称
     */
    private String supplierShortName;

    /**
     * 仕入先連絡先
     */
    private String supplierPhoneNo;

    /**
     * 仕入先担当者
     */
    private String supplierPic;
}
```
</details>

<details>
<summary>SupplierController.java</summary>

```java
package com.example.controller;

import com.example.entity.MstSupplier;
import com.example.form.SupplierForm;
import com.example.service.SupplierService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * 仕入先参照画面のコントローラークラス
 */
@Controller
public class SupplierController {

    @Autowired
    private SupplierService supplierService;

    /**
     * 初期表示処理
     * 
     * @param supplierCode 仕入先コード
     * @param model モデル
     * @return 仕入先参照画面のテンプレート名
     */
    @GetMapping("/supplier/view")
    public String viewSupplier(@RequestParam("supplierCode") String supplierCode, Model model) {
        // 仕入先コードを条件に仕入先情報を取得する
        MstSupplier supplier = supplierService.getSupplierByCode(supplierCode);

        // 取得した仕入先情報をフォームに設定する
        SupplierForm supplierForm = new SupplierForm();
        if (supplier != null) {
            supplierForm.setSupplierCode(supplier.getSupplierCode());
            supplierForm.setSupplierName(supplier.getSupplierName());
            supplierForm.setSupplierShortName(supplier.getSupplierShortName());
            supplierForm.setSupplierPhoneNo(supplier.getSupplierPhoneNo());
            supplierForm.setSupplierPic(supplier.getSupplierPic());
        }

        // モデルにフォームを追加する
        model.addAttribute("supplierForm", supplierForm);

        // 仕入先参照画面を表示する
        return "supplierView";
    }
}
```
</details>

<details>
<summary>action.js</summary>

```java
// 仕入先参照画面のアクション定義

// 閉じるボタンのクリックイベント
document.getElementById('closeButton').addEventListener('click', function() {
    // ポップアップ表示された当画面（仕入先参照画面）を閉じる
    window.close();
});
```
</details>

<details>
<summary>supplierView.html</summary>

```java
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>仕入先参照画面</title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <script src="/static/js/action.js" defer></script>
</head>
<body>
    <div class="container">
        <h1>仕入先参照</h1>
        <form>
            <!-- 仕入先コード -->
            <div class="form-group">
                <label for="supplierCode">仕入先コード：</label>
                <span id="supplierCode">{{supplierForm.supplierCode}}</span>
            </div>

            <!-- 仕入先名 -->
            <div class="form-group">
                <label for="supplierName">仕入先名：</label>
                <span id="supplierName">{{supplierForm.supplierName}}</span>
            </div>

            <!-- 仕入先略称 -->
            <div class="form-group">
                <label for="supplierShortName">仕入先略称：</label>
                <span id="supplierShortName">{{supplierForm.supplierShortName}}</span>
            </div>

            <!-- 仕入先連絡先 -->
            <div class="form-group">
                <label for="supplierPhoneNo">仕入先連絡先：</label>
                <span id="supplierPhoneNo">{{supplierForm.supplierPhoneNo}}</span>
            </div>

            <!-- 仕入先担当者 -->
            <div class="form-group">
                <label for="supplierPic">仕入先担当者：</label>
                <span id="supplierPic">{{supplierForm.supplierPic}}</span>
            </div>

            <!-- 閉じるボタン -->
            <button type="button" id="closeButton" class="btn btn-secondary">閉じる</button>
        </form>
    </div>
</body>
</html>
```
</details>

</details>

### 生成されたプログラムの確認

「生成済プログラム」の各プログラムにカーソルを合わせると、「生成済プログラムコード」に生成されたプログラムが表示されます。
また、「生成済プログラム」の各プログラムをクリックすると、より確認しやすい画面に切り替わります。

![screenshot.9.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/956bc5a0-6445-e2ab-c017-4ca50e881667.jpeg)

![screenshot.10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/1f5b334f-55aa-4d9d-2ae3-49dd2e296722.jpeg)

生成プログラム確認画面でもプログラムを確認することができます。
対象のプログラムを選択し、「プログラム表示」ボタンを押すことで生成されたプログラムを確認できます。

![screenshot.14.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/7339d27e-c4aa-ee86-d6b9-eb5331ab31a8.jpeg)
![screenshot.15.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/d8f4464a-c5be-795b-cab7-ae638ed11f6d.jpeg)


### プログラムの再生成

「再生成」ボタンでプロジェクト全体の再生成を行えます。
また、「このファイルのみ再生成」ボタンでファイル単体の再生成も行えます。

![screenshot.7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/471b012d-5f40-1aad-1d35-7790b7ab35fc.jpeg)
![screenshot.8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957471/8bf05025-39c5-88f4-a41e-2caa01122688.jpeg)

## 生成されたプログラムの注意点

### 100%のプログラムは生成されない
生成AIの性能や設計書の複雑さにも左右されますが、現状では一切修正の必要ないプログラムは生成されないため、最終的に人力での修正が必要になります。

### 生成AIのモデルによる精度のゆれ
選択したモデルによって、生成されるプログラムの質が左右されます。
2024年12月現在では、ChatGPTのo1や4oモデルの使用を推奨しています。

### 

## 次回予告
次回は「生成されたプログラムの修正・改良方法」です。
生成されたプログラムを実際のプロジェクトやリポジトリに反映させる手順を解説していきます。

### 連載一覧　CodeAGIを使って開発を行っていきます。
1. ##### [【連載第1回】CodeAGIで設計書からプログラムまでを自動化する流れを解説します](https://qiita.com/sono1/items/76588de183aaa2a09e3b)
2. ##### [【連載第2回】「CodeAGI」の概要](https://qiita.com/to_sprdx/items/e5a065fe01ec588880af)
3. ##### [【連載第3回】設計書の準備とCodeAGIへの取り込み方法](https://qiita.com/bellpepper/items/c0f71e8c2274ae290041)
4. ##### 【連載第4回】CodeAGIを活用したプログラムの自動生成
5. ##### [【連載第5回】生成されたプログラムの修正・改良方法](https://qiita.com/sono1/items/cc977ae9b71d645ecd59)
6. ##### [【連載第6回】最終動作確認と実行](https://qiita.com/sprdx_c_en/items/b03ed16b237cb35708b5)