0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CodeAGIを使って開発を行っていきます。(連載6回目)

Last updated at Posted at 2025-05-16

【連載第6回】最終動作確認と実行

前回の投稿では、CodeAGIで生成されたコードを修正する方法について紹介しました。本記事では、生成されたプログラムを修正して、実際に動かすまでのステップを紹介していきます。
修正していくプログラムは連載第4回目で生成した「仕入情報照会画面」です。

1. 開発の前提条件

今回の説明は、以下のPC環境を前提に進めていきます。

環境 詳細
OS Windows 11 Home
DB MySQL 8.0.42
JDK JDK 21 (Java SE Development Kit 21)
IDE STS4 (Spring Tools 4 for Eclipse)
ライブラリ Lombok

STS4は「Pleiades」プラグインをインストールして、日本語化しています。

これらのインストール手順については割愛させていただきます。他サイトより手順を確認してください。

2. プロジェクトの雛形を作成

CodeAGIで生成されるプログラムは、それ単体では動かすことができません。
まずはプロジェクトのベースとなる雛形を用意する必要があります。
今回修正していく「仕入情報照会画面」はSpring Bootフレームワークのプロジェクトであるため、STS4から新しいSpringスタータープロジェクトを作成します。

STS4を開き、「ファイル(F) > 新規(N) > Spring スターター・プロジェクト(Spring Initializr)」をクリックしてください。
スクリーンショット 2025-05-13 094132.png

基本情報の設定

表示される「新規 Spring スターター・プロジェクト(Spring Initializr)」ポップアップに、今回のプロジェクト情報を入力していきます。
スクリーンショット 2025-05-13 100747.png

入力項目の簡単な説明をします。

  • サービス URL(Service URL):規定値の「https://start.spring.io」で問題ありません
  • 名前(Name):規定値の「demo」でも構いませんが、今回は「仕入情報照会画面」を作成しようとしているので、「purchaseinquiry」とします
  • タイプ(Type):今回は「Maven」とします
  • Java バージョン(Java Version):PCにインストールしているJDKのバージョンを入力するため、今回は「21」とします
  • パッケージング(Packaging):規定値の「Jar」で問題ありません
  • 言語(Language):規定値の「Java」で問題ありません
  • グループ(Group):規定値の「com.example」で問題ありません
  • 成果物(Artifact):「名前」項目と同じ値を入力してください
    ※「名前」項目を入力すると自動で補完されます
  • バージョン(Version):規定値の「0.0.1-SNAPSHOT」で問題ありません
  • 説明(Description):規定値の「Demo project for Spring Boot」でも構いませんが、今回は「仕入情報照会画面」を作成しようとしているので、「Demo project for Purchase Info Inquiry Screen」とします
  • パッケージ(Package):こちらは、CodeAGIで生成したプログラムのパッケージ構成と同じ形にしたいため、今回は「com.example」とします

入力を終えた後は、「次へ(N)」をクリックしてください。

依存関係の設定

「次へ(N)」をクリックすると、「新規 Spring スターター・プロジェクト依存関係」ポップアップが表示されます。
スクリーンショット 2025-05-14 114410.png

こちらのポップアップで、使用するSpring Bootフレームワークのバージョンと、プロジェクトで使用予定の依存環境を選択します。

「Spring Boot バージョン」は規定値のままで問題ありません。

今回のプロジェクトで使用する依存関係は以下の通りです。

依存関係 詳細
Spring Web Webアプリケーションを構築するための依存関係
Thymeleaf Javaテンプレートエンジン
Spring Data JPA ORM
MySQL Driver MySQLを使用するためのDBドライバー
Lombok アノテーションライブラリ
Validation(検証) ユーザーが入力したデータ(フォーム)を検証する仕組み
Spring Boot DevTools 開発を効率化するためのツールセット(ホットリロードなど)
Spring Boot Actuator デバッグを容易にするための機能を提供

「Spring Boot DevTools」と「Spring Boot Actuator」の選択は任意です。

依存関係の選択が完了しましたら、「完了(F)」をクリックしてください。
作成したSpring Bootのプロジェクトが、画面左側の「パッケージ・エクスプローラー」に表示されます。
スクリーンショット 2025-05-13 141035.png

プロジェクトの雛形が作成できました!

3. 作成した雛形に生成コードを配置

先ほど作成したプロジェクトの雛形に、CodeAGIで生成したプログラムを配置します。
以下に生成したプログラム情報を再掲します。(連載4回目より)

  • Entity.java
    • MstItemCategory.java
    • MstItem.java
    • MstPerson.java
    • MstSupplier.java
    • PurchaseInformation.java
  • SystemApplication.java
    • SystemApplication.java
  • Repository.java
    • MstItemCategoryRepository.java
    • MstItemRepository.java
    • MstPersonRepository.java
    • MstSupplierRepository.java
    • PurchaseInformationRepository.java
  • Service.java
    • PurchaseInformationService.java
    • MstSupplierService.java
    • MstPersonService.java
    • MstItemCategoryService.java
  • Form.java
    • PurchaseInformationSearchForm.java
  • Controller.java
    • PurchaseInformationController.java
  • action.js
    • action.js
  • HTML
    • purchaseInformationSearch.html

連載4回目の記事では、「仕入先参照画面」のコードも生成していますが、本記事では「仕入情報照会画面」の修正のみ行うため、「仕入先参照画面」の掲載を省いています。


CodeAGIからすべてのファイルを出力します。 出力時のフォルダ構成は、このようになっています。
#指定したルートディレクトリ#
├── プロジェクト共通定義
│   └── Spring Boot
│       └── src
│           └── main
│               └── java
│                   └── com
│                       └── example
│                           ├── entity
│                           │   ├── MstItem.java
│                           │   ├── MstItemCategory.java
│                           │   ├── MstPerson.java
│                           │   ├── MstSupplier.java
│                           │   └── PurchaseInformation.java
│                           └── SystemApplication.java
│
└── 仕入情報照会画面
    └── Spring Boot
        └── src
            └── main
                ├── java
                │   └── com
                │       └── example
                │           ├── repository
                │           │   ├── MstItemCategoryRepository.java
                │           │   ├── MstItemRepository.java
                │           │   ├── MstPersonRepository.java
                │           │   ├── MstSupplierRepository.java
                │           │   └── PurchaseInformationRepository.java
                │           ├── service
                │           │   ├── MstItemCategoryService.java
                │           │   ├── MstPersonService.java
                │           │   ├── MstSupplierService.java
                │           │   └── PurchaseInformationService.java
                │           ├── form
                │           │   └── PurchaseInformationSearchForm.java
                │           └── controller
                │               └── PurchaseInformationController.java
                └── resources
                    ├── static
                    │   └── js
                    │       └── action.js
                    └── templates
                        └── purchaseInformationSearch.html

それぞれのファイルをプロジェクトの雛形に配置すると、下の画像のようになります。
スクリーンショット 2025-05-13 165419.png

プロジェクトの雛形を作成したときについてきた「PurchaseinquiryApplication.java」は、「SystemApplication.java」と内容が同等であるため、この段階で削除してあります。

4. データベースの設定

データベースの設定を行わないとプロジェクトを起動することができません。そのため、まずはデータベースの設定から行っていきましょう。

MySQL側の設定

今回のプロジェクトではORMとして「Spring Data JPA」を使用しているため、テーブルの作成は事前に行っておく必要はありません。しかし、データベースは作成しておく必要があります。

コマンドプロンプトからMySQLにログインして、下のコードを実行してください。※データベース名は「PURCHASE_INFO_DEMO」としています。

CREATE DATABASE PURCHASE_INFO_DEMO;

これで、MySQL側での設定は完了です。

Spring Bootプロジェクト側の設定

データベースとの接続に必要な情報は、
「src/main/resources/application.properties」
ファイルに記載していきます。

プロジェクトの雛形を作る段階で自動的に作成されますが、中身は一行のコードのみとなっています。

application.properties
spring.application.name=purchaseinquiry

application.propertiesの内容を以下のように書き換えます。

application.properties
spring.application.name=purchaseinquiry

# --- 1. Database config properties ---
spring.datasource.url=jdbc:mysql://localhost:3306/PURCHASE_INFO_DEMO
spring.datasource.username={ユーザー名}
spring.datasource.password={パスワード}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# -------------------------------------

# --- 2. JPA config ---
spring.jpa.hibernate.ddl-auto=update
# ---------------------

コードの簡単な説明をします。

  • 「1. Database config properties」には、MySQLとの接続に必要な情報を記載します
    • spring.datasource.url:今回のプロジェクトで使用する、MySQL内のデータベースへのURLを指定します
    • spring.datasource.username:ログイン用のユーザー名を指定します
    • spring.datasource.password:ログイン用のパスワードを指定します
    • spring.datasource.driver-class-name:MySQLのDBドライバーを指定します
  • 「2. JPA config」には、ORMの設定を記載します。
    • spring.jpa.hibernate.ddl-auto:「update」を指定することで、プロジェクトを実行したときに、テーブルが自動で生成・更新されます。

これでひとまずデータベースの設定は終わりです。 あとはプロジェクトを実行することができれば、データベースにEntityクラスに対応したテーブルが自動的に作成されます。

次のステップでは、プロジェクトを実行できるようになるまでの流れを説明します。

5. プロジェクトの実行

プロジェクトを実行するには、プログラム内で構文エラーとなっている部分をすべて修正する必要があります。

STS4の「パッケージ・エクスプローラー」を確認すると、以下のパッケージ内でエラーが発生しています。

  • com.example.entity
  • com.example.form
  • com.example.controller

今回発生しているエラー内容は、全ファイルで共通していて、import文でエラーが出ています。jakartaパッケージからインポートするべきところが、javaxパッケージになっています。
javax」という記載をすべて「jakarta」に置き換えます。

// 例) MstItem.java
- import javax.persistence.*;
+ import jakarta.persistence.*;

// 例) PurchaseInformationSearchForm.java
- import javax.validation.constraints.Size;
+ import jakarta.validation.constraints.Size;

// 例) PurchaseInformationController.java
- import javax.validation.Valid;
+ import jakarta.validation.Valid;

これでプロジェクトの実行を妨げている構文エラーはすべて消えました。

CodeAGIで生成したコードが、「jakarta」ではなく「javax」で実装されてしまう問題を回避するためには、以下の2つの方法をお試しください。(100%回避できるわけではありません)

  • プロジェクト依存環境のJavaのバージョンを明示的に設定する
    プロジェクト依存環境
  • 最新の生成AIモデルを使用してプログラム生成する

ではプロジェクトを実行してみましょう。
STS4の画面左下に位置する「Boot ダッシュボード」から、今回のプロジェクト(purchaseinquiry)を選択して実行してみます。
スクリーンショット 2025-05-14 104354.png

画面下部の「コンソール」に下の画像のような表示が出ていれば、プロジェクトの実行は成功です!
スクリーンショット 2025-05-14 104909.png

この時点で、MySQLにテーブルが作成されます。

mysql> show tables;
+------------------------------+
| Tables_in_purchase_info_demo |
+------------------------------+
| mst_item                     |
| mst_item_category            |
| mst_person                   |
| mst_supplier                 |
| purchase_information         |
+------------------------------+

6. 初期表示

先ほどのステップで、プロジェクトを実行することができました。
このステップでは、ブラウザに「仕入情報照会画面」を表示できるようになるまでの流れを説明します。

URLの確認

今回生成した「仕入情報照会画面」がどのURLで表示されるのかは、Controller.javaのコードを確認することで判断できます。

PurchaseInformationController.java
package com.example.controller;

import com.example.form.PurchaseInformationSearchForm;
// ...

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

    // ...

    /**
     * 初期表示処理
     *
     * @param model モデル
     * @return 仕入情報照会画面
     */
    @GetMapping("/search")
    public String init(Model model) {
        // ...
    }

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

ファイル内のアノテーション(@~)を確認すると、

  • クラスに「@RequestMapping("/purchase")
  • 初期表示処理メソッドに「@GetMapping("/search")

となっています。

したがって、今回の初期表示用のURLは、このようになります。
http://localhost:8080/purchase/search

初期表示までの修正点

どのURLで「仕入情報照会画面」を表示できるのかは確認できました。しかし、今の状態でURLにアクセスしようとすると、エラーが出てしまいます。エラーの原因を修正していきましょう。

「PurchaseInformationController.java」ファイルの内容を確認すると、クラスの各メソッドに「return "purchase/search";」というコードがあります。
Controllerクラスのメソッドの戻り値は、HTMLテンプレートへのファイルパスにしないといけません。
生成された「仕入情報照会画面」のHTMLファイルは、templatesフォルダ直下に配置した「purchaseInformationSearch.html」だけです。そのため、このようにコードを書き換えます。

- return "purchase/search";
+ return "purchaseInformationSearch";

間違っていた6ヵ所を書き換え、「http://localhost:8080/purchase/search」にアクセスしてみます。
スクリーンショット 2025-05-14 142200.png

画面を表示することができました!

Bootstrap CSSの反映

画面を表示することはできましたが、デザインがまるっきり抜けてしまっています。

この原因は、HTMLファイルでインポートしているBootstrap CSSへのパスが間違っているためです。

purchaseInformationSearch.html
<!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>
    <!-- ... -->
</body>

</html>

今回はBootstrap CSSをローカル環境にダウンロードしていないため、CDN経由でインポートする方法に変更します。

- <link rel="stylesheet" href="/css/bootstrap.min.css">
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">

変更後、ブラウザをリフレッシュすると、デザインが反映された状態の「仕入情報照会画面」が表示されます。
スクリーンショット 2025-05-14 142138.png

7. 設計書通りに修正

ここからは、「仕入情報照会画面」が設計書通りに動くように、プログラムを修正していきます。

action.jsの削除

今回のプロジェクトでは、JavaScriptのコードは不要です。そのため、「purchaseInformationSearch.html」から「action.js」へのリンクを削除します。
<head>タグ内から<script>タグの記載を消してください。

- <script src="/js/action.js"></script>

Formオブジェクトのリンク

HTMLとController間でFormオブジェクトの受け渡しができるように、「PurchaseInformationController.java」の検索処理メソッドを修正します。
メソッド定義を以下のように書き換えます。

- public String search(@Valid PurchaseInformationSearchForm form, BindingResult result, Model model) {
+ public String search(@Valid @ModelAttribute("searchForm") PurchaseInformationSearchForm form, BindingResult result, Model model) {

メソッドの引数でFormクラスを指定しているところに、「@ModelAttribute("searchForm")」を追加しました。この修正により、画面から検索処理を実行したときに、フォームの入力値をController側に渡すことができます。
※このアノテーションの引数には、HTMLとController間で受け渡しするFormオブジェクトの識別名を定義する必要があります。そのため、ここで定義した名前をHTML側でも使用してください。

セッションスコープに保存

「PurchaseInformationController.java」の初期表示処理メソッドでは、マスタデータとFormオブジェクトをリクエストスコープに保存しています。このままでは、アプリで画面遷移があったときに、保存していた値が消えてしまいます。
したがって、セッションスコープに保存するようにコードを修正します。

// ...

+ import org.springframework.web.bind.annotation.SessionAttributes;
+ import java.time.LocalDate;
+ import java.time.temporal.TemporalAdjusters;

// ...

/**
 * 仕入情報コントローラークラス
 */
@Controller
+ @SessionAttributes({"suppliers", "persons", "itemCategories", "searchForm"})
@RequestMapping("/purchase")
public class PurchaseInformationController {

    // ...

+   @ModelAttribute("suppliers")
+   public List<MstSupplier> suppliers() {
+   	// 仕入先リストを取得
+   	return mstSupplierService.getAllSuppliers();
+   }
    
+   @ModelAttribute("persons")
+   public List<MstPerson> persons() {
+   	// 担当者リストを取得
+   	return mstPersonService.getAllPersons();
+   }
    
+   @ModelAttribute("itemCategories")
+   public List<MstItemCategory> itemCategories() {
+   	// 商品種別リストを取得
+   	return mstItemCategoryService.getAllItemCategories();
+   }
    
+   @ModelAttribute("searchForm")
+   public PurchaseInformationSearchForm searchForm() {
+   	PurchaseInformationSearchForm searchForm = new PurchaseInformationSearchForm();
+   	// フォームの仕入開始日と仕入終了日に値を自動で入力
+   	LocalDate today = LocalDate.now();
+   	searchForm.setStartDate(today.with(TemporalAdjusters.firstDayOfMonth()));
+   	searchForm.setEndDate(today.with(TemporalAdjusters.lastDayOfMonth()));
+   	return searchForm;
+   }

    /**
     * 初期表示処理
     *
     * @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 "purchaseInformationSearch";
    }

この変更に伴って、「purchaseInformationSearch.html」のコードもセッションスコープから値を読み取るように修正します。

<!-- 仕入先 -->
- ${suppliers}"
+ ${session.suppliers}"

<!-- 仕入担当者 -->
- ${persons}"
+ ${session.persons}"

<!-- 商品種別 -->
- ${itemCategories}"
+ ${session.itemCategories}"

日付型の変換

アプリ全体で使用している日付型が、今では非推奨の「java.util.Date」になっています。これらをすべて「java.time.LocalDate」に変更していきます。
修正箇所は、以下のファイルです。

  • Entity.java
    修正ファイル:「MstItemCategory.java」、「MstItem.java」、「MstPerson.java」、「MstSupplier.java」、「PurchaseInformation.java」
    // 例)PurchaseInformation.java
    - import java.util.Date;
    + import java.time.LocalDate;
    
    // ...
    
    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    - @Temporal(TemporalType.TIMESTAMP)
    - private Date editDatetime;
    + private LocalDate editDatetime;
    
    // 他にも2フィールドを修正
    
    ※「java.util.Date」の廃止に伴って、「@Temporal」アノテーションの削除も行っています。

  • Repository.java
    修正ファイル:「PurchaseInformationRepository.java」
    - import java.util.Date;
    + import java.time.LocalDate;
    
    // ...
    
    List<PurchaseInformation> findByCriteria(
            @Param("supplierCode") String supplierCode,
            @Param("purchasePic") String purchasePic,
    -       @Param("startDate") Date startDate,
    +       @Param("startDate") LocalDate startDate,
    -       @Param("endDate") Date endDate,
    +       @Param("endDate") LocalDate endDate,
            @Param("itemCategory") String itemCategory,
            @Param("itemName") String itemName);
    


  • Service.java
    修正ファイル:「PurchaseInformationService.java」
    - import java.util.Date;
    + import java.time.LocalDate;
    
    // ...
    
    - public List<PurchaseInformation> searchPurchaseInformation(String supplierCode, String purchasePic, Date startDate, Date endDate, String itemCategory, String itemName) {
    + public List<PurchaseInformation> searchPurchaseInformation(String supplierCode, String purchasePic, LocalDate startDate, LocalDate endDate, String itemCategory, String itemName) {
        return purchaseInformationRepository.findByCriteria(supplierCode, purchasePic, startDate, endDate, itemCategory, itemName);
    }
    


  • Form.java
    修正ファイル:「PurchaseInformationSearchForm.java」
    - import java.util.Date;
    + import java.time.LocalDate;
    
    // ...
    
    /**
     * 仕入開始日
     */
    - @DateTimeFormat(pattern = "yyyy/MM/dd")
    + @DateTimeFormat(pattern = "yyyy-MM-dd")
    - private Date startDate;
    + private LocalDate startDate;
    
    // 仕入終了日のフィールドも同じように修正する
    
    ※「@DateTimeFormat」アノテーションのコードも修正しました。(HTMLのフォームに入力する日付の形と、Controller側で受け取る日付の形が異なっていたため)

最後に、HTMLのコードも修正する必要があります。
「purchaseInformationSearch.html」ファイルの「#dates.~」というコードを「#temporals.~」に変更します。

<!-- 仕入日 -->
<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')}">
+   <input type="date" id="startDate" name="startDate" class="form-control" th:value="${#temporals.format(searchForm.startDate, 'yyyy-MM-dd')}">
</div>

<!-- 他の2ヵ所も修正する -->

※「#dates」は「java.util.Date」などを扱うユーティリティで、「#temporals」は「java.time.LocalDate」などを扱うユーティリティとなっています。

HTML側に渡す検索結果(DTO対応)

画面側で表示するデータと、データベースから取得されるデータが異なっています。

HTML側 DB取得結果
商品コード
商品名
商品種別
仕入先
仕入日
仕入単価
仕入数量
仕入金額
仕入担当者名

仕入番号
仕入日
仕入先コード
商品コード
仕入単価
仕入担当者
登録者
登録日時
更新者
更新日時

この違いをなくすために、今回はDTOクラスを新しく定義します。
具体的には、「com.example.dto」パッケージを作成して、そのパッケージに「PurchaseInformationDto.java」ファイルを作成します。

「パッケージ・エクスプローラー」からプロジェクトを右クリックし、「新規(W) > パッケージ」をクリックして、新しいパッケージを作成します。
スクリーンショット 2025-05-15 103527.png
「名前(M)」欄に「com.example.dto」と入力し、「完了(F)」をクリックしてください。

次に、新しいDTOクラスを作成します。
「パッケージ・エクスプローラー」から「com.example.dto」パッケージを右クリックし、「新規(W) > クラス」をクリックします。
スクリーンショット 2025-05-15 110839.png
「名前(M)」欄に「PurchaseInformationDto」と入力し、「完了(F)」をクリックしてください。

作成された「PurchaseInformationDto.java」ファイルの内容はこのようにします。

PurchaseInformationDto.java
package com.example.dto;

import java.time.LocalDate;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PurchaseInformationDto {
	
	/**
     * 商品コード
     */
    private String itemCode;
    
    /**
     * 商品名
     */
    private String itemName;
    
    /**
     * 商品種別
     */
    private String itemCategory;
    
    /**
     * 仕入先
     */
    private String supplierName;

    /**
     * 仕入日
     */
    private LocalDate purchaseDate;

    /**
     * 仕入単価
     */
    private Integer purchaseUnitPrice;

    /**
     * 仕入数量
     */
    private Integer purchaseQuantity;

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

※HTML側で表示するデータ名と、DTO側で定義するフィールド名が一致するようにしてください。

それでは、新しいDTOクラスを使用するように他のファイルも修正します。

  • Repository.java
    修正ファイル:「PurchaseInformationRepository.java」
    // ...
    
    + import com.example.dto.PurchaseInformationDto;
    
    // ...
    
    - @Query("SELECT pi FROM PurchaseInformation pi " +
    + @Query("SELECT new com.example.dto.PurchaseInformationDto(" + 
    +   	"mi.itemCode, mi.itemName, mic.itemCategoryName, ms.supplierName, pi.purchaseDate, pi.purchaseUnitPrice, pi.purchaseQuantity, mp.personName) " + 
    +   	"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(
    + List<PurchaseInformationDto> findByCriteria(
    // ...
    
    ※SQL文のSELECT内もDTO対応に伴って修正しています。

  • Service.java
    修正ファイル:「PurchaseInformationService.java」
    // ...
    
    - import com.example.entity.PurchaseInformation;
    + import com.example.dto.PurchaseInformationDto;
    
    // ...
    
    - public List<PurchaseInformation> searchPurchaseInformation(String supplierCode, String purchasePic, LocalDate startDate, LocalDate endDate, String itemCategory, String itemName) {
    + public List<PurchaseInformationDto> searchPurchaseInformation(String supplierCode, String purchasePic, LocalDate startDate, LocalDate endDate, String itemCategory, String itemName) {
        return purchaseInformationRepository.findByCriteria(supplierCode, purchasePic, startDate, endDate, itemCategory, itemName);
    }
    


  • Controller.java
    修正ファイル:「PurchaseInformationController.java」
    // ...
    
    - import com.example.entity.PurchaseInformation;
    + import com.example.dto.PurchaseInformationDto;
    
    // ...
    
    // 検索処理
    - List<PurchaseInformation> purchaseInformationList = purchaseInformationService.searchPurchaseInformation(
    + List<PurchaseInformationDto> purchaseInformationList = purchaseInformationService.searchPurchaseInformation(
            form.getSupplierCode(),
            form.getPurchasePic(),
            form.getStartDate(),
            form.getEndDate(),
            form.getItemCategory(),
            form.getItemName()
    );
    
    // ...
    

DB検索用SQLの最終調整

画面側から送られてくる「仕入先」、「仕入担当者」、「商品種別」、「商品名」の値が未選択(空文字)の場合は、データベースの抽出条件から外さないと、空文字のデータを検索するSQL文が発行されてしまいます。
そのため、「PurchaseInformationRepository.java」のSQL文を修正します。

// ...

 /**
 * 検索条件に基づいて仕入情報を取得するクエリ
 * 
 * @param supplierCode 仕入先コード
 * @param purchasePic 仕入担当者
 * @param startDate 仕入開始日
 * @param endDate 仕入終了日
 * @param itemCategory 商品種別
 * @param itemName 商品名
 * @return 仕入情報のリスト
 */
@Query("SELECT new com.example.dto.PurchaseInformationDto(" + 
        "mi.itemCode, mi.itemName, mic.itemCategoryName, ms.supplierName, pi.purchaseDate, pi.purchaseUnitPrice, pi.purchaseQuantity, mp.personName) " + 
        "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) " +
+       "WHERE (:supplierCode IS NULL OR :supplierCode = '' OR pi.supplierCode = :supplierCode) " +
-       "AND (:purchasePic IS NULL OR pi.purchasePic = :purchasePic) " +
+       "AND (:purchasePic IS NULL OR :purchasePic = '' 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 (:itemCategory IS NULL OR :itemCategory = '' OR mi.itemCategory = :itemCategory) " +
-       "AND (:itemName IS NULL OR mi.itemName LIKE %:itemName%) " +
+       "AND (:itemName IS NULL OR :itemName = '' OR mi.itemName LIKE %:itemName%) " +
        "ORDER BY pi.supplierCode, pi.purchaseDate")
List<PurchaseInformation> findByCriteria(
// ...

HTMLの最終調整

フォーム内のドロップダウン要素から、「th:field="項目への参照"」というコードが抜けているため、画面遷移が発生した場合に入力内容が保持されません。
「purchaseInformationSearch.html」のコードを修正します。

<!-- ... -->

- <select id="supplierCode" name="supplierCode" class="form-control">
+ <select id="supplierCode" name="supplierCode" th:field="*{supplierCode}" class="form-control">
    
<!-- ... -->

- <select id="purchasePic" name="purchasePic" class="form-control">
+ <select id="purchasePic" name="purchasePic" th:field="*{purchasePic}" class="form-control">

<!-- ... -->

- <select id="itemCategory" name="itemCategory" class="form-control">
+ <select id="itemCategory" name="itemCategory" th:field="*{itemCategory}" class="form-control">

<!-- ... -->

また、検索結果表示テーブルのフォーマット変換処理コードにも誤りがあるため、そちらも修正します。

<!-- ... -->

- <td th:text="${#numbers.formatInteger(info.purchaseUnitPrice, '###,###,##0')}">仕入単価</td>
+ <td th:text="${#numbers.formatInteger(info.purchaseUnitPrice, 3, 'COMMA')}">仕入単価</td>
- <td th:text="${#numbers.formatInteger(info.purchaseQuantity, '###,###,##0')}">仕入数量</td>
+ <td th:text="${#numbers.formatInteger(info.purchaseQuantity, 3, 'COMMA')}">仕入数量</td>
- <td th:text="${#numbers.formatInteger(info.purchaseUnitPrice * info.purchaseQuantity, '###,###,##0')}">仕入金額</td>
+ <td th:text="${#numbers.formatInteger(info.purchaseUnitPrice * info.purchaseQuantity, 3, 'COMMA')}">仕入金額</td>

<!-- ... -->

8. 最後に

これですべての修正が終わりました。あとはデータベースの各テーブルにテスト用データを追加すれば、「仕入情報照会画面」が動作します。
スクリーンショット 2025-05-15 153343.png

CodeAGIを使用すれば、テストデータの生成も簡単にできます。
テストデータ生成についての説明は、本記事では割愛させていただきますが、未来の投稿では詳細に説明させていただきます!

各ファイルの修正後の内容はこちらです。

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

import lombok.Data;
import jakarta.persistence.*;
import java.time.LocalDate;

/**
 * 商品マスタ
 */
@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")
    private LocalDate registDatetime;

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

    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    private LocalDate editDatetime;
}
MstItemCategory.java
MstItemCategory.java
// MstItemCategory.java
package com.example.entity;

import lombok.Data;
import jakarta.persistence.*;
import java.time.LocalDate;

// 商品種別マスタ
@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")
    private LocalDate registDatetime;

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

    // 更新日時
    @Column(name = "EDIT_DATETIME")
    private LocalDate editDatetime;
}
MstPerson.java
MstPerson.java
// MstPerson.java
package com.example.entity;

import lombok.Data;
import jakarta.persistence.*;
import java.time.LocalDate;

/**
 * 担当者マスタ
 */
@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")
    private LocalDate registDatetime;

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

    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    private LocalDate editDatetime;
}
MstSupplier.java
MstSupplier.java
// MstSupplier.java
package com.example.entity;

import lombok.Data;
import jakarta.persistence.*;
import java.time.LocalDate;

/**
 * 仕入先マスタ
 */
@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")
    private LocalDate registDatetime;

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

    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    private LocalDate editDatetime;
}
PurchaseInformation.java
PurchaseInformation.java
// PurchaseInformation.java
package com.example.entity;

import lombok.Data;
import jakarta.persistence.*;
import java.time.LocalDate;

/**
 * 仕入情報エンティティクラス
 * テーブル名: 仕入情報
 */
@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)
    private LocalDate 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")
    private LocalDate registDatetime;

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

    /**
     * 更新日時
     */
    @Column(name = "EDIT_DATETIME")
    private LocalDate editDatetime;
}
PurchaseInformationRepository.java
PurchaseInformationRepository.java
package com.example.repository;

import com.example.dto.PurchaseInformationDto;
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.time.LocalDate;
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 new com.example.dto.PurchaseInformationDto(" + 
			"mi.itemCode, mi.itemName, mic.itemCategoryName, ms.supplierName, pi.purchaseDate, pi.purchaseUnitPrice, pi.purchaseQuantity, mp.personName) " + 
			"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 :supplierCode = '' OR pi.supplierCode = :supplierCode) " +
            "AND (:purchasePic IS NULL OR :purchasePic = '' 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 :itemCategory = '' OR mi.itemCategory = :itemCategory) " +
            "AND (:itemName IS NULL OR :itemName = '' OR mi.itemName LIKE %:itemName%) " +
            "ORDER BY pi.supplierCode, pi.purchaseDate")
    List<PurchaseInformationDto> findByCriteria(
            @Param("supplierCode") String supplierCode,
            @Param("purchasePic") String purchasePic,
            @Param("startDate") LocalDate startDate,
            @Param("endDate") LocalDate endDate,
            @Param("itemCategory") String itemCategory,
            @Param("itemName") String itemName);
}
PurchaseInformationService.java
PurchaseInformationService.java
package com.example.service;

import com.example.dto.PurchaseInformationDto;
import com.example.repository.PurchaseInformationRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
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<PurchaseInformationDto> searchPurchaseInformation(String supplierCode, String purchasePic, LocalDate startDate, LocalDate endDate, String itemCategory, String itemName) {
        return purchaseInformationRepository.findByCriteria(supplierCode, purchasePic, startDate, endDate, itemCategory, itemName);
    }
}
PurchaseInformationSearchForm.java
PurchaseInformationSearchForm.java
package com.example.form;

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

import jakarta.validation.constraints.Size;
import java.time.LocalDate;

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

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

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

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

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

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

    /**
     * 商品名
     */
    @Size(max = 50, message = "商品名は最大50文字までです。")
    private String itemName;
}
PurchaseInformationDto.java
PurchaseInformationDto.java
package com.example.dto;

import java.time.LocalDate;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PurchaseInformationDto {
	
	/**
     * 商品コード
     */
    private String itemCode;
    
    /**
     * 商品名
     */
    private String itemName;
    
    /**
     * 商品種別
     */
    private String itemCategory;
    
    /**
     * 仕入先
     */
    private String supplierName;

    /**
     * 仕入日
     */
    private LocalDate purchaseDate;

    /**
     * 仕入単価
     */
    private Integer purchaseUnitPrice;

    /**
     * 仕入数量
     */
    private Integer purchaseQuantity;

    /**
     * 仕入担当者名
     */
    private String purchasePic;
}
PurchaseInformationController.java
PurchaseInformationController.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.dto.PurchaseInformationDto;
import com.example.entity.MstItemCategory;
import com.example.entity.MstPerson;
import com.example.entity.MstSupplier;

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.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;

import jakarta.validation.Valid;

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.List;

/**
 * 仕入情報コントローラークラス
 */
@Controller
@SessionAttributes({"suppliers", "persons", "itemCategories", "searchForm"})
@RequestMapping("/purchase")
public class PurchaseInformationController {

    @Autowired
    private PurchaseInformationService purchaseInformationService;

    @Autowired
    private MstSupplierService mstSupplierService;

    @Autowired
    private MstPersonService mstPersonService;

    @Autowired
    private MstItemCategoryService mstItemCategoryService;
    
    @ModelAttribute("suppliers")
    public List<MstSupplier> suppliers() {
    	// 仕入先リストを取得
    	return mstSupplierService.getAllSuppliers();
    }
    
    @ModelAttribute("persons")
    public List<MstPerson> persons() {
    	// 担当者リストを取得
    	return mstPersonService.getAllPersons();
    }
    
    @ModelAttribute("itemCategories")
    public List<MstItemCategory> itemCategories() {
    	// 商品種別リストを取得
    	return mstItemCategoryService.getAllItemCategories();
    }
    
    @ModelAttribute("searchForm")
    public PurchaseInformationSearchForm searchForm() {
    	PurchaseInformationSearchForm searchForm = new PurchaseInformationSearchForm();
        // フォームの仕入開始日と仕入終了日に値を自動で入力
    	LocalDate today = LocalDate.now();
    	searchForm.setStartDate(today.with(TemporalAdjusters.firstDayOfMonth()));
    	searchForm.setEndDate(today.with(TemporalAdjusters.lastDayOfMonth()));
    	return searchForm;
    }

    /**
     * 初期表示処理
     *
     * @param model モデル
     * @return 仕入情報照会画面
     */
    @GetMapping("/search")
    public String init(Model model) {
        return "purchaseInformationSearch";
    }

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

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

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

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

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

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

        return "purchaseInformationSearch";
    }
}
purchaseInformationSearch.html
purchaseInformationSearch.html
<!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 href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</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" th:field="*{supplierCode}" class="form-control">
                    <option value="">選択してください</option>
                    <option th:each="supplier : ${session.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" th:field="*{purchasePic}" class="form-control">
                    <option value="">選択してください</option>
                    <option th:each="person : ${session.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="${#temporals.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="${#temporals.format(searchForm.endDate, 'yyyy-MM-dd')}">
            </div>

            <!-- 商品種別 -->
            <div class="form-group">
                <label for="itemCategory">商品種別:</label>
                <select id="itemCategory" name="itemCategory" th:field="*{itemCategory}" class="form-control">
                    <option value="">選択してください</option>
                    <option th:each="category : ${session.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="${#temporals.format(info.purchaseDate, 'yyyy/MM/dd')}">仕入日</td>
                        <td th:text="${#numbers.formatInteger(info.purchaseUnitPrice, 3, 'COMMA')}">仕入単価</td>
                        <td th:text="${#numbers.formatInteger(info.purchaseQuantity, 3, 'COMMA')}">仕入数量</td>
                        <td th:text="${#numbers.formatInteger(info.purchaseUnitPrice * info.purchaseQuantity, 3, 'COMMA')}">仕入金額</td>
                        <td th:text="${info.purchasePic}">仕入担当者名</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</body>

</html>
application.properties
application.properties
spring.application.name=purchaseinquiry

# --- 1. Database config properties ---
spring.datasource.url=jdbc:mysql://localhost:3306/PURCHASE_INFO_DEMO
spring.datasource.username={ユーザー名}
spring.datasource.password={パスワード}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# -------------------------------------

# --- 2. JPA config ---
spring.jpa.hibernate.ddl-auto=update
# ---------------------

本連載「CodeAGIを使って開発を行っていきます。」は、今回が最終回となります。
最後までお読みいただき、ありがとうございました!:raised_hands:


「CodeAGI」の詳細については、以下のリンクをご覧ください:
👉 https://codeagi.ai/


連載一覧 CodeAGIを使って開発を行っていきます。

  1. 【連載第1回】CodeAGIで設計書からプログラムまでを自動化する流れを解説します
  2. 【連載第2回】「CodeAGI」の概要
  3. 【連載第3回】設計書の準備とCodeAGIへの取り込み方法
  4. 【連載第4回】CodeAGIを活用したプログラムの自動生成
  5. 【連載第5回】生成されたプログラムの修正・改良方法
  6. 【連載第6回】最終動作確認と実行
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?