JavaのJDBCでデータベースに接続して、サーブレット・JSPを用いた「商品在庫管理アプリ」を作成しました。

<h1>開発したアプリケーションの概要</h1>
商品の在庫の管理が行えるというコンセプトのアプリケーションの作成を行いました。
これは「管理者」「ユーザー」でのログインを行うことができ、それぞれ行える操作が異なる。

・管理者が行える操作

①	登録：データ（商品名・分類・説明・在庫数）の登録ができる。
②	検索：商品名でのデータの検索ができる。
③	複数の削除：選択を複数押してからのまとめて削除ができる。
④	編集：編集リンクを押してデータ（商品名・分類・説明・在庫数）を入力して書き換えることができる。

・ユーザーが行える操作
①	検索：管理者が作成したデータから商品名で検索を行い、別画面に遷移し、検索結果を表示する。


<h2>★使った技術</h2>
MySQL：商品データを保存するためのデータベースを提供する。
また、商品に関する情報（商品名、分類、説明、在庫数）を格納するテーブルを作成やSQLを使用して、データの登録・検索・削除・編集の操作を行う。 

・MySQLでの具体的なadmin_tbテーブル作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/28e97f3e-3fc9-85b0-f15e-ff4c1e72b6c5.png)

・テーブルに要素を挿入した後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/38629474-7642-c688-04d6-7b2474b5f3fd.png)

・MySQLでの具体的なuser_tbテーブル作成
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/80b801ce-d90e-c4f2-ccc1-f2d0537eaae1.png)

・テーブルに要素を挿入した後
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/d6477f10-8148-b8fa-a37b-0fde352f0737.png)


・MySQLでの具体的なproduct_tbテーブル作成
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/e4108b03-1487-725d-4e93-a5d1406d04a1.png)

・テーブルに要素を挿入した後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/2ba1d90a-a1d5-2d5d-cc05-585854761210.png)

・HTML + CSS + JSP
HTML：アプリケーションの基本的なページ構造を作成。各ページで入力やボタンクリックなどの要素を定義する。
CSS：スタイルを整えて視覚的に見やすいデザインを作り、ユーザー満足度を上げる。
JSP：サーバーサイドで動的にHTMLを生成するために使用する。JSPでは、Javaの構文（for文やif文）を埋め込み、動的な処理を実現する。管理者からのリクエストに応じて、商品データの表示やフォーム入力結果を反映させる。 

・JDBC：アプリケーションとデータベース間の橋渡し役として機能し、SQL文をJavaコード内で記述し、 その結果もJavaコード内で受け取ることができる。これによって、MySQLで行っているデータベース操作（登録・更新・削除・検索）をプログラム内で簡単に実行でき、動的なWebアプリケーションの作成が可能となる。


・サーブレット：Webサーバー上で実行されるJavaプログラムで、管理者・ユーザからのリクエスト（doGetメソッド・doPostメソッド）を受け取り、別で定義したクラスのJavaプロジェクトに詳細の処理をしてもらう。必要な処理を、別クラスのJavaにしてもらった後、その結果をJSPに渡し、JSPは動的なHTMLを生成しブラウザに表示する。

・doGetメソッドとは
GETリクエストは、画面を表示するための情報をサーバーから取得する際に使われるリクエストのことで、このリクエストを処理する役割を持つメソッドである。

・doPostメソッドとは
POSTリクエストは、ブラウザからサーバーにデータを送信するために使用されるリクエストのことで、HTTP POSTリクエストを処理するために使用されるメソッドである。


★画面構成
①　初期画面
管理者でログインのボタンを選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/af331c88-1856-bc3b-e50d-fa0e996ff16f.png)

②	管理者ログイン画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/889c4ee4-35bd-49a9-61c5-5f02f72bc080.png)
正しい管理者ID「１」・パスワード「aaaa」は、データベースのadmin_tbに格納されているもの。ログインを押すとAdminServlet.Javaに飛ぶようにJSPに設定をしている。

・違っている場合は？
正しいのは、admin_tbに登録したID：1とパスワード「aaaa」のみそれ以外を入れると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/61cdb4d5-3e6b-a25a-a913-fdbfa55edb5b.png)
このようにエラーを出すようにしている。
③	管理者ログイン後画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/914988e6-7a0f-ad4b-c95a-ebad67783171.png)

ログインに成功すると、③の画面に遷移する。
ここで表示されているテーブルは、MySQLで登録されているproduct_tbをブラウザに表示させている。

④	検索機能について
例：入力フォームに「スマホ」と入力する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/da474054-ae0e-0fa3-ac92-8f3af39cf8aa.png)
検索ボタンを押すと、
商品名がスマホのものだけが、抽出されそのテーブルをjspで表示させている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/c59007b5-16f9-5b7a-bf53-9d880930f577.png)

⑤	まとめて削除できる機能について
例：商品ID　4・5にチェックを入れ、「まとめて削除」を押してみると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/14d83517-54c8-5e39-a216-9bf055ccb7d8.png)

結果：選択された商品IDのテーブルの列が削除されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/38858f1e-0150-ede0-f746-dbd46c449c5e.png)

データベースも見てみると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/8201f748-0e82-1201-4ee9-c7d1192a810e.png)
選択された商品ID４・５の、product_id＝４・５が削除されているのが確認できる。

⑥	編集機能について
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/9f6f6f65-d9bd-7a91-a9f1-4ac7733e67ef.png)

商品ID１の情報を取得し、それを編集するproduct_update.jspへ遷移する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/1ae700ef-4ebd-eef5-c725-e734c45d443b.png)


例　「商品名：Mac」 「分類：機械b」　「説明：最新式のパソコン」 「在庫数：500」に変えてみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/f94e267a-28d2-8c82-3115-f3020e8a28c6.png)

結果：商品ID１の列が書き換わっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/924f60df-c53b-69d1-c2c8-dc26e193aa3f.png)

データベースも見てみると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/58211a5f-28a9-2156-aa29-e3c9a0dca85c.png)
選択された商品ID１の、product_id＝１が書き換わっているのが確認できる。

⑦	商品登録機能について
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/682c62ca-723c-3a59-8a82-c6790c23f5a8.png)
ProductRegisterServletへ行き、データベースに情報を登録した後、その結果をJSPに反映させる。

例 「商品名：ルンバ」 「分類：機械f」　「説明：AI付き全自動でルートを計算」 
「在庫数：179」を登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/e6ad15d1-3048-734d-4930-e943ad8497ea.png)

結果：商品ID１３として新しいテーブルの列が登録されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/f8f04e43-8303-1fea-c7fc-e00e5c823ca0.png)


データベースも見てみると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/901e3171-ef01-e646-a890-9be9b9be5cd6.png)
product_id = 13として新しいデータが登録されているのが確認される。

⑧ ユーザーログイン画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/4f06b66a-7996-0221-3e33-ba93bdbb45bb.png)
正しいユーザーID・パスワードは、MySQLのuser_tbに格納されている。
user_id = 2とpassword = bbbbを入力フォームに入れる+どの管理者IDの管理しているテーブルを見るのかの3つをフォームに入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/048c7c49-f992-c55d-be95-0d4260727589.png)

・ユーザーID・パスワード・管理者IDのどれかを間違うと、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/c71590d6-694a-35b7-5aef-a43bbb3d94f8.png)
エラーを出すようにし、userlogin.jspでとどまり、ログイン成功時のuserproduct_list.jspへ遷移しないようにしている。


⑨ ユーザーログイン後画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/f2210a60-5205-94dd-484f-11d87f77ab44.png)
userproduct_list.jspへ行き、ユーザーは、管理者が操作したテーブルのデータの内容を見ることが出来る。
そして商品名による検索によって、データを絞り込む操作を行うことができる。

<h2>★クラス構成</h2>
configパッケージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/6f024b10-f9b5-ce01-decf-3b74e80f3b5f.png)


DBconfig.javaクラス
このクラスは、データベース接続に必要な情報（URL、ユーザー名、パスワード）を取得し、それらの情報を必要とする別のクラスに渡す役割がある。
属性
private Properties dbinfo = new Properties();
Propertiesクラスは、Java標準ライブラリのクラスで、java.utilパッケージに属している。
なので、import java.util.Properties;でインポートしている。
Propertiesオブジェクトを作成し、それをdbinfoという変数に代入する。
コンストラクタ DBconfig()を定義し、その中で
①	Dbconfig.propertiesファイルを相対パス(config/dbconfig.properties)で読み込む。
②	プロパティファイルがない場合はエラーを返してreturnで処理を終える。
③	プロパティファイルから読み取った情報をdbinfoの中にload()関数を使って格納する。

メソッド
・getUrl（）：プロパティファイルからデータベースの接続先URLを取得して必要とするクラスに返す。
・getUser（）：プロパティファイルからデータベースの接続ユーザー名を取得して必要とするクラスに返す。
・getPassword（）：プロパティファイルからデータベースの接続パスワードを取得して必要とするクラスに返す。


```Java

package config;

import java.io.InputStream;
import java.util.Properties;

public class DBconfig {
    private Properties dbinfo = new Properties();
    
    public DBconfig() {
        dbinfo = new Properties();
        
        // プロパティファイルを相対パスで読み込む
        try (InputStream input = getClass().getClassLoader().getResourceAsStream("config/dbconfig.properties")) {
            if (input == null) {
                System.out.println("プロパティファイルが見つかりません");
                return;
            }
            dbinfo.load(input);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // プロパティファイルの内容を返す
    public String getUrl() {
        return dbinfo.getProperty("url");
    }

    public String getUser() {
        return dbinfo.getProperty("user");
    }

    public String getPassword() {
        return dbinfo.getProperty("password");
    }
}
```

objectパッケージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/0046fab9-a53a-b09b-838b-02e4b7e7a515.png)

・Admin.javaクラス
このクラスは、データベースの管理者情報を管理するクラスである。
属性
・管理者ID（admin_id）：管理者を識別するための数値型ID。
・管理者名（name）：管理者の名前を文字列型で保持。
・パスワード(password)：管理者の名前を文字列型で保持。
・ログイン状態の判断（login_flag）：管理者が現在ログインしているかどうかの真偽値（trueかfalse）を保持。
(admin_id、name、password、login_flag)は、すべてprivateと宣言し、外部からのアクセスを禁じている。代わりに、属性のアクセスは専用のゲッター・セッター（getId（）、setId（）、getName（）、setName（）など）を通じてアクセスすることで、セキュリティを意識したカプセル化の設計を行っている。

```Java
package object;

public class Admin {
	 private int admin_id;           // 管理者ID
	 private String name;            // 管理者名
	 private String password;        // パスワード
	 private boolean login_flag;
	 
//	 ゲッターとセッター
	 public int getId() {
		 return admin_id;
	 }
	 
	 public void setId(int admin_id) {
		 this.admin_id = admin_id;
	 }
	 
	 public String getName() {
		 return name;
	 }
	 
	 public void setName(String name) {
		 this.name = name;
	 }
	 
	 public String getPassword() {
		 return password;
	 }
	 
	 public void setPassword(String password) {
		 this.password = password;
	 }
	 
	 public boolean getLogin_flag() {
		 return login_flag;
	 }
	 
	 public void setLogin_flag(boolean login_flag) {
		 this.login_flag = login_flag;
	 }
}

```

・Product.javaクラス・User.javaクラス
この2つのクラスもAdminクラスと同様に、それぞれデータベースの商品情報・ユーザー情報を管理するクラスである。
これらのクラスもそれぞれの属性をprivateにし、ゲッター・セッターメソッドを通して、属性にアクセスできるようにしたカプセル化の設計を行っている。

Productクラス
```Java
package object;

import java.util.Date;

public class Product {
	
	private int product_id;
	private int admin_id;
	private String product_name;
	private String category;
	private String explanation;
	private int quantity;
	private Date registered_time;
	private Date updated_time;
	
	
	public int getProductid() {
		return product_id;
	}
	public void setProductid(int product_id) {
		this.product_id = product_id;
	}
	public int getAdminid() {
		return admin_id;
	}
	public void setAdminid(int admin_id) {
		this.admin_id = admin_id;
	}
	public String getProductName() {
		return product_name;
	}
	public void setProductName(String product_name) {
		this.product_name = product_name;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
	
	public String getExplanation() {
		return explanation;
	}
	public void setExplanation(String explanation) {
		this.explanation = explanation;
	}
	public int getQuantity() {
		return quantity;
	}
	public void setQuantity(int quantity) {
		this.quantity = quantity;
	}
	public Date getRegistered_time() {
		return registered_time;
	}
	public void setRegistered_time(Date registered_time) {
		this.registered_time = registered_time;
	}
	public Date getUpdated_time() {
		return updated_time;
	}
	public void setUpdated_time(Date updated_time) {
		this.updated_time = updated_time;
	}

}

```

Userクラス
```Java
package object;
public class User {
	 private int user_id;           // 管理者ID
	 private String name;            // 管理者名
	 private String password;        // パスワード
	 private boolean login_flag;
	 
//	 ゲッターとセッター
	 
	 public int getId() {
		 return user_id;
	 }
	 
	 public void setId(int user_id) {
		 this.user_id = user_id;
	 }
	 
	 public String getName() {
		 return name;
	 }
	 
	 public void setName(String name) {
		 this.name = name;
	 }
	 
	 public String getPassword() {
		 return password;
	 }
	 
	 public void setPassword(String password) {
		 this.password = password;
	 }
	 
	 public boolean getLogin_flag() {
		 return login_flag;
	 }
	 
	 public void setLogin_flag(boolean login_flag) {
		 this.login_flag = login_flag;
	 }
}

```

sqlパッケージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/74ed817c-703e-e377-03cd-0f3e0e7e59b5.png)

・Login.javaクラス
メソッド①
check(String admin_id, String password)
説明：
管理者IDとパスワードを受け取り、認証を行う。そしてデータベースに対してSQLクエリを実行し、認証結果をAdminオブジェクトに格納して返す。
処理概要：
①	DBconfigクラスからデータベース接続情報を取得する。
②	データベースに接続する。
③	管理者IDとパスワードでSQLクエリを実行する。
④	結果をAdminクラスのインスタンスに格納する。
⑤	認証成功ならlogin_flagをtrueに設定し、認証失敗ならfalseに設定する。
メソッド②
getProductInfo(String admin_id)
説明：
管理者IDを受け取り、その管理者が管理している商品情報を取得する。その結果をproductオブジェクトのリストに格納して返す。
処理概要：
①	DBconfigクラスからデータベース接続情報を取得する。
②	データベースに接続する。
③	管理者IDを使ってSQLクエリを実行する。
④	結果をProductクラスのインスタンスに格納する。
⑤	取得した商品情報をリストに追加して返す。

```Java
package sql;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import config.DBconfig;
import object.Admin;
import object.Product;

public class Login {
	public Admin check(String admin_id, String password) throws FileNotFoundException {
		
//		データベースへの接続情報をプロパティファイルから取得
		DBconfig db_info = new DBconfig();
		String url = db_info.getUrl();
		String user = db_info.getUser();
		String pass = db_info.getPassword();
		
//		実行するSQL文
		String login_sql = "SELECT * FROM admin_tb WHERE admin_id = ? AND password = ?";
		
//		管理者クラスのインスタンスを生成
		Admin admin = new Admin();
		 
//		データベースへの接続 try catch文
		try {
			// MySQLドライバを手動でロード（
			Class.forName("com.mysql.cj.jdbc.Driver");

			// データベースへの接続
			try (Connection conn = DriverManager.getConnection(url, user, pass)) {
				PreparedStatement stmt = conn.prepareStatement(login_sql);
				stmt.setString(1, admin_id); // 1つ目のパラメータにadmin_idをセット
				stmt.setString(2, password); // 2つ目のパラメータにpasswordをセット
				
				ResultSet rs = stmt.executeQuery(); // SQLを実行
				
				// 結果をAdminオブジェクトに格納
				if (rs.next()) {
					admin.setId(rs.getInt("admin_id"));
					admin.setName(rs.getString("name"));
					admin.setPassword(rs.getString("password"));
					admin.setLogin_flag(true);
				} else {
					admin.setLogin_flag(false);
				}
			} catch (SQLException e) {
				// SQLエラー処理
				System.out.println("管理者データベース接続エラー");
				e.printStackTrace();
			}
		} catch (ClassNotFoundException e) {
			// ドライバが見つからない場合
			System.out.println("MySQLドライバが見つかりません");
			e.printStackTrace();
		}
//		データベースから取得した値を返す
		return admin;
		
	}
	
//	ログイン成功した後に管理者が管理している製品情報の取得
public List<Product> getProductInfo(String admin_id) throws FileNotFoundException {
//	データベースへの接続情報をプロパティファイルから取得
	DBconfig db_info = new DBconfig();
	String url = db_info.getUrl();
	String user = db_info.getUser();
	String pass = db_info.getPassword();
	
//	実行SQL文
//	admin_idで該当する製品情報をproduct_tbから取得する
	String product_sql = "SELECT * FROM product_tb WHERE admin_id = ?";
	
//	型をProductにした新しい配列を定義し、ここに製品情報を格納する
//	product型のオブジェクトにすることでより分かりやすく安全にリストを定義している
	List<Product> pro_list = new ArrayList<Product>();
	
	try {
		// MySQLドライバを手動でロード（必要な場合）
		Class.forName("com.mysql.cj.jdbc.Driver");
//		データベースへ接続
		try (Connection conn = DriverManager.getConnection(url, user, pass)) {
			PreparedStatement stmt = conn.prepareStatement(product_sql);
			
			stmt.setString(1, admin_id);
			ResultSet rs = stmt.executeQuery();
			
//		　SQL実行後 リストに格納
			while(rs.next()) {
//				クラスのインスタンスに一時格納
				Product product_info = new Product();
				product_info.setProductid(rs.getInt("product_id"));
				product_info.setAdminid(rs.getInt("admin_id"));
				product_info.setProductName(rs.getString("product_name"));
				product_info.setCategory(rs.getString("category"));
				product_info.setExplanation(rs.getString("explanation"));
				product_info.setQuantity(rs.getInt("quantity"));
				product_info.setRegistered_time(rs.getDate("registered_time"));
				product_info.setUpdated_time(rs.getDate("updated_time"));
				pro_list.add(product_info);
			}
			
		} catch (SQLException e) {
			System.out.println("管理者格納データベース接続エラー");
			e.printStackTrace();
		}
	} catch (ClassNotFoundException e) {
		System.out.println("MySQLドライバが見つかりません");
		e.printStackTrace();
	}
	return pro_list;
}	
}
```

・Register.javaクラス
メソッド
product_register(int admin_id, String product_name, String category, String explanation, int quantity)
説明：
指定された管理者IDに紐づく商品情報をデータベースに登録する。

処理概要：
①	DBconfigクラスからデータベース接続情報を取得する。
②	データベースに接続する。
③	SQL文（INSERT INTO product_tb）を定義し、SQLクエリを実行する。
④	SQLの実行が成功した場合、commitを行い、データベースの変更を確定する。しかし、SQL実行中に例外が発生した場合、rollbackを実行し、トランザクションを取り消す。

```Java
package sql;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import config.DBconfig;

public class Register {
	public void product_register(int admin_id, String product_name, String category, String explanation, int quantity) throws FileNotFoundException {
		
//		データベースへの接続情報をプロパティファイルから取得
		DBconfig db_info = new DBconfig();
		String url = db_info.getUrl();
		String user = db_info.getUser();
		String pass = db_info.getPassword();
		
//		実行するSQL文
		String register_sql = "INSERT INTO product_tb (admin_id, product_name, category, explanation, quantity) "
				+ "VALUES(?,?,?,?,?)";
		
//		データベースの接続
		
		try (Connection conn = DriverManager.getConnection(url,user,pass)) {
			// オートコミット機能を無効化
			conn.setAutoCommit(false);

			try (PreparedStatement stmt = conn.prepareStatement(register_sql)) {
				
//				?の部分に挿入
				stmt.setInt(1, admin_id);
				stmt.setString(2, product_name);
				stmt.setString(3, category);
				stmt.setString(4, explanation);
				stmt.setInt(5, quantity);
				
				 // SQLの実行
				stmt.executeUpdate();

				// コミット
				conn.commit();
				System.out.println("コミット処理を行いました");
			} catch (SQLException e) {
				conn.rollback();
				System.out.println("ロールバック処理を行いました");
				e.printStackTrace();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
	}
	
}

```


・Search.javaクラス
メソッド
product_search(String name)
説明：
指定された文字列を商品名に含むすべての商品情報をデータベースから検索して返す。
処理概要：
①	DBconfigクラスからデータベース接続情報を取得する。
②	データベースに接続する。
③	SQL文(SELECT * FROM product_tb WHERE product_name LIKE ?)を準備して、SQLクエリを実行する。
④	検索結果を各商品情報のリスト(products)に追加する。
⑤	SQLの実行が成功した場合、commitを行い、データベースの変更を確定する。しかし、SQL実行中に例外が発生した場合、rollbackを実行し、トランザクションを取り消す。

```Java
package sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import config.DBconfig;
import object.Product;

public class Search {
	public List<Product> product_search(String name) {
		List<Product> products = new ArrayList<Product>();
//		データベースの接続情報をプロパティファイルから取得
		DBconfig db_info = new DBconfig();
		String url = db_info.getUrl();
		String user = db_info.getUser();
		String pass = db_info.getPassword();
		
		String search_sql ="SELECT * FROM product_tb WHERE product_name LIKE ?";
		
		try (Connection conn = DriverManager.getConnection(url,user,pass)) {
			// オートコミット機能を無効化
			conn.setAutoCommit(false);
			try (PreparedStatement stmt = conn.prepareStatement(search_sql)) {
				stmt.setString(1, "%" + name + "%");
				ResultSet rs = stmt.executeQuery();
				
				while(rs.next()) {
					Product product = new Product();
					product.setProductid(rs.getInt("product_id"));
					product.setProductName(rs.getString("product_name"));
					product.setCategory(rs.getString("category"));
					product.setExplanation(rs.getString("explanation"));
					product.setQuantity(rs.getInt("quantity"));
					product.setRegistered_time(rs.getDate("registered_time"));
					product.setUpdated_time(rs.getDate("updated_time"));
		            products.add(product);
				}
				// コミット処理
                conn.commit();
				
			} catch (SQLException e) {
				conn.rollback();
				System.out.println("検索SQLのロールバック処理を行いました");
				e.printStackTrace();
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		return products;
		
	}

}
```


・SelectOneProduct.javaクラス
メソッド
get_One_Product_Info(int product_id)
説明：
編集リンクを押したとき、指定されたproduct_idに対応する商品情報をデータベースから取得して返す。
処理概要：
①	DBconfigクラスからデータベース接続情報を取得する。
②	データベースに接続する。
③	SQL文（SELECT * FROM product_tb WHERE product_id = ?）を定義して、SQLクエリを実行する。
④	ResultSetの内容を反復処理し、Productクラスのインスタンス(one_product)に対応する列の値を設定する。

```Java
package sql;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import config.DBconfig;
import object.Product;

public class SelectOneProduct {
	public Product get_One_Product_Info(int product_id) throws FileNotFoundException {
//		データベースへの接続情報をプロパティファイルから取得
		DBconfig db_info = new DBconfig();
		String url = db_info.getUrl();
		String user = db_info.getUser();
		String pass = db_info.getPassword();
		
		Product one_product = new Product();
		
//		実行SQL
		String one_product_sql = "SELECT * FROM product_tb WHERE product_id = ?";
		
		try (Connection conn = DriverManager.getConnection(url, user, pass)) {
			PreparedStatement stmt = conn.prepareStatement(one_product_sql);
			
			stmt.setInt(1, product_id);
			ResultSet rs = stmt.executeQuery();
			
			while(rs.next()) {
				one_product.setProductid(rs.getInt("product_id"));
				one_product.setProductName(rs.getString("product_name"));
				one_product.setCategory(rs.getString("category"));
				one_product.setExplanation(rs.getString("explanation"));
				one_product.setQuantity(rs.getInt("quantity"));
			}
			
		} catch (SQLException e) {
			System.out.println("データベースとの接続を閉じる");
			e.printStackTrace();
		}
		
		
		return one_product;
	}

}

```

・SomeDeleteProduct.javaクラス
メソッド
productsome_delete(String[] productIds)
説明：
指定された複数の商品（product_id）をデータベースから一括削除するための機能を提供する。
処理概要：
①	DBconfigクラスからデータベース接続情報を取得する。
②	データベースに接続する。
③	SQLクエリ(DELETE FROM product_tb WHERE product_id IN (?, ?, ?))を動的に構築する。指定された複数のproduct_idを削除するため、DELETE文にIN演算子を使用して、プレースホルダーを動的に生成する。
④	プレースホルダーに product_id を順番に設定し、SQL文を実行する。
⑤	SQLの実行が成功した場合、トランザクションをコミットする。

```Java
package sql;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import config.DBconfig;

public class SomeDeleteProduct {
	public void productsome_delete(String[] productIds) throws FileNotFoundException {
		
		//データベースへの接続情報をプロパティファイルから取得
		DBconfig db_info = new DBconfig();
		String url = db_info.getUrl();
		String user = db_info.getUser();
		String pass = db_info.getPassword();
		
//		実行するSQL文 プレースホルダーを動的に作成
		StringBuilder deleteSql = new StringBuilder("DELETE FROM product_tb WHERE product_id IN (");   
		
		for (int i = 0; i < productIds.length; i++) {
			deleteSql.append("?");
			if (i < productIds.length - 1) {
				deleteSql.append(",");
			}
		}
		deleteSql.append(")");
		
//		データベースへ接続
		try(Connection conn = DriverManager.getConnection(url, user, pass)) {
			// オートコミット機能を無効化
            conn.setAutoCommit(false);
			
			try (PreparedStatement stmt = conn.prepareStatement(deleteSql.toString())) {
//				パラメータを設定
				for (int i = 0; i < productIds.length; i++) {
					stmt.setInt(i + 1, Integer.parseInt(productIds[i]));
				}
				
				int rs = stmt.executeUpdate();
				conn.commit();
				System.out.println(rs + "件の商品データを削除しました。");
				
			} catch (SQLException e) {
//				ロールバック処理
				conn.rollback();
				 System.err.println("ロールバック処理を行いました: " + e.getMessage());
	             throw new RuntimeException("データ削除中にエラーが発生しました。", e);
			}
			
		} catch (SQLException e1) {
			 System.err.println("DB接続に失敗しました: " + e1.getMessage());
	         throw new RuntimeException("データベース接続中にエラーが発生しました。", e1);
		} 
	}
}

```

・Update.javaクラス
メソッド
product_update(String product_name, String category, String explanation, int quantity, int product_id)
説明：
特定の商品情報をデータベース上で更新するための機能を提供する。
処理概要：
①	DBconfigクラスからデータベース接続情報を取得する。
②	データベースに接続する。
③	更新用SQLクエリ(UPDATE product_tb set product_name = ?, category = ?,  explanation = ?, quantity = ? WHERE product_id = ?)UPDATE文を定義する。
④	プレースホルダーに各引数の値をセットしてSQLクエリを実行する。
⑤	SQLの実行が成功した場合、トランザクションをコミットする。

```Java
package sql;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import config.DBconfig;

public class Update {
	public void product_update(String product_name, String category, String explanation, int quantity, int product_id) throws FileNotFoundException {
//		データベースへの接続情報をプロパティファイルから取得
		DBconfig db_info = new DBconfig();
		String url = db_info.getUrl();
		String user = db_info.getUser();
		String pass = db_info.getPassword();
		
//		実行SQL
		String update_sql = "UPDATE product_tb set product_name = ?, category = ?,  explanation = ?, quantity = ? WHERE product_id = ?";
		
		
		try (Connection conn = DriverManager.getConnection(url,user,pass)) {
			// オートコミット機能を無効化
			conn.setAutoCommit(false);
			
			try (PreparedStatement stmt = conn.prepareStatement(update_sql)) {
				stmt.setString(1, product_name);
				stmt.setString(2, category);
				stmt.setString(3, explanation);
				stmt.setInt(4,quantity);
				stmt.setInt(5, product_id);
				
				// SQLの実行
				stmt.executeUpdate();
				//コミット
				conn.commit();
				System.out.println("編集更新処理が成功しました");
				
			} catch(SQLException e) {
				conn.rollback();
			    System.out.println("編集のロールバック処理を行いました");
				e.printStackTrace();
			}
		} catch(SQLException e1) {
			e1.printStackTrace();
		}
		
	}
	
}

```

・UserLogin.javaクラス
メソッド①
check_user(String user_id, String password)
説明：
user_idとpasswordを基に、ユーザーの認証を行う。データベースに保存された情報と照合し、認証に成功した場合はユーザー情報を返す。認証に失敗した場合は、login_flagを false に設定した User オブジェクトを返す。
処理概要：
①	DBconfigを使用してデータベース接続情報を取得する。
②	データベースに接続する。
③	user_tb テーブルから、ユーザーIDとパスワードが一致するレコードを検索。
④	該当レコードがあれば、User オブジェクトに値を格納し、login_flag を true に設定する、該当レコードがなければ、login_flagをfalseに設定する。

メソッド②
getuserProductInfo(String admin_id)
説明：
指定された管理者IDに紐づく商品情報をデータベースから取得する。商品情報をproductオブジェクトに格納し、それらをリストとして返す。管理者が管理する全商品の詳細情報を取得し、ブラウザに表示をする。
処理概要：
①	DBconfigを使用してデータベース接続情報を取得する。
②	データベースに接続する。
③	product_tb テーブルから、指定された管理者IDに紐づく商品情報を取得する。
④	結果を Product オブジェクトに格納し、リストに追加して返す。

メソッド③
checkAdminExist(String admin_id)
説明：
指定された管理者IDがデータベースのadmin_tbに存在するかを確認する。
存在する場合は、trueを返し、存在しない場合は、falseを返す。falseの場合、ブラウザにエラーメッセージ(管理者が存在しない)を表示する　。
処理概要：
①	DBconfigを使用してデータベース接続情報を取得する。
②	データベースに接続する。
③	admin_tb テーブルから、指定された管理者IDを検索。
④	結果が存在する場合はtrueを返す。結果がなければfalseを返す。

```Java
package sql;

import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import config.DBconfig;
import object.Product;
import object.User;

public class UserLogin {
	public User check_user(String user_id, String password) throws FileNotFoundException {
		
//		データベースへの接続情報をプロパティファイルから取得
		DBconfig db_info = new DBconfig();
		String url = db_info.getUrl();
		String user = db_info.getUser();
		String pass = db_info.getPassword();
		
//		実行するSQL文
		String loginuser_sql = "SELECT * FROM user_tb WHERE user_id = ? AND password = ?";
		 
		User usering = new User();
		
		try(Connection conn = DriverManager.getConnection(url, user, pass)) {
			PreparedStatement stmt = conn.prepareStatement(loginuser_sql);
			stmt.setString(1, user_id); 
			stmt.setString(2, password); 
			
			ResultSet rs = stmt.executeQuery();
			
			if (rs.next()) {
				usering.setId(rs.getInt("user_id"));
				usering.setName(rs.getString("name"));
				usering.setPassword(rs.getString("password"));
				usering.setLogin_flag(true);
			} else {
				usering.setLogin_flag(false);
			}
		} 
		catch(SQLException e) {
			System.out.println("ユーザー認証データベース接続エラー");
			e.printStackTrace();
			
		} 
		
		return usering;
		
	}
	public List<Product> getuserProductInfo(String admin_id) throws FileNotFoundException {
		DBconfig db_info = new DBconfig();
		String url = db_info.getUrl();
		String user = db_info.getUser();
		String pass = db_info.getPassword();
		
		String product_sql = "SELECT * FROM product_tb WHERE admin_id = ?";
		
		List<Product> pro_list = new ArrayList<Product>();
		
		try {
			// MySQLドライバを手動でロード（必要な場合）
			Class.forName("com.mysql.cj.jdbc.Driver");
//			データベースへ接続
			try (Connection conn = DriverManager.getConnection(url, user, pass)) {
				PreparedStatement stmt = conn.prepareStatement(product_sql);
				
				stmt.setString(1, admin_id);
				ResultSet rs = stmt.executeQuery();
				
//			　SQL実行後 リストに格納
				while(rs.next()) {
//					クラスのインスタンスに一時格納
					Product product_info = new Product();
					product_info.setProductid(rs.getInt("product_id"));
					product_info.setAdminid(rs.getInt("admin_id"));
					product_info.setProductName(rs.getString("product_name"));
					product_info.setCategory(rs.getString("category"));
					product_info.setExplanation(rs.getString("explanation"));
					product_info.setQuantity(rs.getInt("quantity"));
					product_info.setRegistered_time(rs.getDate("registered_time"));
					product_info.setUpdated_time(rs.getDate("updated_time"));
					
					pro_list.add(product_info);
				}
				
			} catch (SQLException e) {
				System.out.println("ユーザーデータベース接続エラー");
				e.printStackTrace();
			}
		} catch (ClassNotFoundException e) {
			System.out.println("MySQLドライバが見つかりません");
			e.printStackTrace();
		}
		
		
		return pro_list;
	}
	public boolean checkAdminExist(String admin_id) {
		DBconfig db_info = new DBconfig();
	    String url = db_info.getUrl();
	    String user = db_info.getUser();
	    String pass = db_info.getPassword();
	    
	    String query = "SELECT * FROM admin_tb WHERE admin_id = ?";
	    
	    try (Connection conn = DriverManager.getConnection(url, user, pass);
	         PreparedStatement stmt = conn.prepareStatement(query)) {
	        
	        stmt.setInt(1, Integer.parseInt(admin_id));
	        ResultSet rs = stmt.executeQuery();
	        
	        // 結果があれば管理者が存在する
	        return rs.next();
	    } catch (SQLException e) {
	        e.printStackTrace();
	    }
	    
	    return false; 
		
	}
		
}
	

```

servletパッケージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/513685d9-bc78-4cb2-6382-4517101b57f0.png)

・AdminServlet.javaクラス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/9bd17467-a1f9-036e-9e6c-58c6b4c9861d.png)

このログインを押したときに、AdminServletクラスに飛ぶようにlogin.jspのformタグに記述している。このサーブレットには、doGet・doPostメソッドが定義されている。

・doGetメソッド：
First.htmlからのGETリクエストを受け取り、adminServletはdoGetメソッドを実行する。RequestDispatcherを使用してログイン画面（login.jsp）に転送を行う。これによって、ブラウザにログイン画面（login.jsp）が表示される。

・doPostメソッド：
login.jspにあるフォームに入力されたデータ（admin_idとpassword）が、POSTリクエストとしてAdminServletに送信される。POSTリクエストを受け取って、AdminServletのdoPostメソッドで処理が行われる。
※具体的な処理内容：
①　フォーム入力値の取得：
request.getParameter() を使って、ログインフォームから送信された管理者ID（admin_id）とパスワード（password）を取得する。
②　ログインしているかの確認：
Login クラスの check() メソッドを呼び出して、IDとパスワードで認証を行う。その結果を Adminクラスのインスタンスadminに格納する。
③　ログイン成功時：
admin.getLogin_flag() が true の場合、ログイン成功と判断し、セッションオブジェクトを作成し、セッションスコープに管理者情報を格納するlogin.getProductInfo(admin_id) を使って、管理者IDに関連する商品の情報のSQL文を実行し、pro_listを返し、リクエストスコープに格納する。そして、product_list.jspがセッションスコープからそれらの情報を取得し、ブラウザに表示する。
ログイン失敗時：
認証に失敗した場合、エラーメッセージをリクエストスコープに格納し、login.jspがそのエラーメッセージを表示し、画面の遷移をそのままにする。

```Java
package servlet;

import java.io.IOException;
import java.util.List;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import object.Admin;
import object.Product;
import sql.Login;


@WebServlet("/AdminServlet")
public class AdminServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/login.jsp");
		dispatcher.forward(request, response);
	}
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 文字コードの設定
		response.setContentType("text/html; charset=UTF-8");
		request.setCharacterEncoding("UTF-8");
		
//		ログイン画面で入力された値を取得
		String admin_id = request.getParameter("admin_id");
		String password = request.getParameter("password");
		
//		ログイン処理の実装 ログインクラスのインスタンス生成
//		ログインクラスのcheckメソッドでデータベースにnameとpasswordがあるかを確認
//		checkの引数にログイン画面で入力された値を格納する
//		それをAdminクラスの変数に代入
		Login login = new Login();
		Admin admin = login.check(admin_id, password);
		
//		ログイン成功時
		if (admin.getLogin_flag()) {
			System.out.println("ログイン成功");
			
//			ログイン成功時にセッションオブジェクトを作成する
			HttpSession admin_session = request.getSession(true);
//			セッションに管理者情報を格納
			admin_session.setAttribute("admin", admin);
			
			
			List<Product> product = null;
//			データベースから取得した顧客情報を格納
			product = login.getProductInfo(admin_id);
			request.setAttribute("product", product);
			
			RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/product_list.jsp");
			dispatcher.forward(request, response);
		} else {
//			ログイン失敗 エラーを表示
			request.setAttribute("errorMsg","管理者ID または パスワードが違います");
			RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/login.jsp");
			dispatcher.forward(request, response);
		}
	}

}

```

サーブレットと他クラスとJSPの関係性のイメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/48296a66-946d-d739-68e6-023a00889a5a.png)


・ProductRegisterServlet.javaクラス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/06c7a9c0-bfca-da36-f44a-291f728aca98.png)

登録するというボタンを押したときにProductRegisterServletに飛ぶように設定している。

・doGetメソッド：
product_list.jspにある
<a  href="<%=request.getContextPath() %>/ProductRegisterServlet">商品登録画面へ</a>このリンクをクリックすると、ProductRegisterServletにGETリクエストを送る。
ProductRegisterServletは、doGetメソッドで、RequestDispatcherを使用して商品登録画面（product_register.jsp）に転送を行う。これによって、ブラウザに商品登録画面（product_register.jsp）が表示される。


・doPostメソッド：
product_register.jspにあるフォームに入力されたデータ（product_name・category・explanation・quantity）が、POSTリクエストとしてProductRegisterServletに送信される。POSTリクエストを受け取って、ProductRegisterServletが、商品登録処理を行い、その後、
登録された商品リストを表示する処理を実行する。
※具体的な処理
① フォームデータの取得：フォームから送信されたrequest.getParameter()を使って、
商品名（product_name）、分類（category）、説明（explanation）、量(quantity)の情報を取得する。
② セッションスコープから管理者情報の取得：
セッションスコープから前に格納された管理者情報の取得をする。

③ 商品登録処理：
Registerクラスのインスタンスを生成し、それのメソッドproduct_registerを実行する。これによって入力されたデータをデータベースに登録する処理を行っている。
④ 更新された商品リストの再取得：
Loginクラスのインスタンスを生成し、それのgetProductInfoメソッドを実行し、登録され新しくなったテーブルのデータをデータベースから取得する。
⑤	商品リストの情報をリクエストスコープに格納する。
⑥	商品リスト画面にリクエストを転送する。これによって、データを新しく登録した新しいテーブルを表示するproduct_list.jspに遷移するということになる。

```Java
package servlet;

import java.io.IOException;
import java.util.List;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import object.Admin;
import object.Product;
import sql.Login;
import sql.Register;

@WebServlet("/ProductRegisterServlet")
public class ProductRegisterServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;


	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//		製品登録画面へ行く
		RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/product_register.jsp");
		dispatcher.forward(request, response);
	}

//	入力された情報を取得してデータベースへ商品情報を登録する
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 文字コードの設定
		response.setContentType("text/html; charset=UTF-8");
		request.setCharacterEncoding("UTF-8");
		
		String product_name = request.getParameter("product_name");
		String category = request.getParameter("category");
		String explanation = request.getParameter("explanation");
		String quantityStr = request.getParameter("quantity"); 
//		intに型変換
		int quantity = Integer.parseInt(quantityStr);
		
//		管理者のセッションを取得
		HttpSession session = request.getSession(true);
		Admin admin = (Admin) session.getAttribute("admin");
		
		Register register = new Register();
		
//		商品登録処理を実行
		register.product_register(admin.getId(), product_name, category ,explanation, quantity);
		
		Login login = new Login();
		List<Product> product = null;
		
//		データベースから取得した情報を格納
		product = login.getProductInfo(String.valueOf(admin.getId()));
		
//		jspへこれらの情報を渡す
		request.setAttribute("product", product);
		
		
		RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/product_list.jsp");
		dispatcher.forward(request, response);
		
	}

}

```

サーブレットと他クラスとJSPの関係性のイメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/21e9022b-887e-4825-5db5-ac8f8eef8bae.png)


・ProductUpdateServlet.javaクラス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/5a2941bd-af38-71d8-029f-6251182a2389.png)

編集するというボタンを押したときにProductUpdateServletに飛ぶように設定している。

・doGetメソッド
①	リクエストパラメータから商品IDを取得：
URLに含まれるリクエストパラメータからproduct_idを取得する。編集を押したときその商品IDを取得する。
今回、商品IDを編集リンク（aタグ）でProductUpdateServletに渡すために、今回は、JSTLを使用している。
JSTL（JavaServer Pages Standard Tag Library）とはJSPでよく使われる機能をタグライブラリとしてまとめたもの。
JSTLを使用するために、2種類のファイル
（jakarta.servlet.jsp.jstl-2.0.0.jarとjakarta.servlet.jsp.jstl-api-3.0.2.jar）をダウンロード
し、libファイルに入れる必要がある。
   「編集URL」を押したとき、product_update.jspには、「商品リスト一覧画面（product_list.jsp）」から「商品編集画面(product_update.jsp)」へ遷移し、その時に選択  　 した商品IDをリンクのパラメータに設定してProductUpdateServletでその商品IDを取得するということを行っている。
②	商品情報の取得：
SelectOneProductクラスのインスタンスを生成し、get_One_Product_Infoメソッドを呼び出し、取得したproduct_idに対応する商品の詳細情報を取得する。
③	リクエストスコープに商品情報を格納し、product_update.jspのgetAttributeでリクエストスコープの中の商品情報を取得する。

④	Product_update.jspにリクエストを転送して、選んだ一つの商品情報を保持した状態で、商品編集画面へ遷移する。今回は、ユーザーがリンクから、誤って商品IDを変更したり、削除したりすることを防ぐために、フォームには表示しないが、サーバーに送信する値として送るため、formタグにhiddenを加えている。

・doPostメソッド
product_update.jspにあるフォームに入力されたデータ（product_name、category、explanation、quantity）とリンクのパラメータproduct_idが、POSTリクエストとしてProductUpdateServletに送信される。POSTリクエストを受け取って、ProductUpdateServletのdoPostメソッドで処理が行われる。
※具体的な処理
①	リクエストパラメータと入力フォームから編集データを取得：
getParameter()を使って、リンクとHTMLフォームから送信された各商品情報を取得する。
②	商品情報の更新処理：
Updateクラスのインスタンスを生成し、product_updateメソッドを呼び出し、doGetメソッドで取得したproduct_idに対応する商品情報の更新をデータベース上で行う。
③	管理者のセッションを取得：
現在ログインしている管理者のセッション情報を取得する。
④	更新後の商品リストを取得：
セッションスコープに格納されているセッション情報の管理者IDをもとに、loginクラスのインスタンスを生成し、getProductInfoメソッドを呼び出し、更新された商品リストを取得する。
⑤	リクエストスコープに商品リストを格納し、getRequestDispatcherで、product_list.jspにリクエストを転送する。product_list.jspは、リクエストスコープから更新された情報を取得して、その内容をブラウザに表示する。

サーブレットと他クラスとJSPの関係性のイメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/1ad06949-62c0-7bac-8b27-3ba9fceaa46c.png)

```Java
package servlet;

import java.io.IOException;
import java.util.List;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import object.Admin;
import object.Product;
import sql.Login;
import sql.SelectOneProduct;
import sql.Update;

@WebServlet("/ProductUpdateServlet")
public class ProductUpdateServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

//	顧客編集画面への遷移
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 文字コードの設定
		response.setContentType("text/html; charset=UTF-8");
		request.setCharacterEncoding("UTF-8");
		
//		編集リンクから商品IDを取得
		int id = Integer.parseInt(request.getParameter("product_id"));
		
		SelectOneProduct one_product = new SelectOneProduct();
//		リンクで選択された商品情報を取得する
		Product product = one_product.get_One_Product_Info(id);
		
		request.setAttribute("product", product);
		
		RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/product_update.jsp");
		dispatcher.forward(request, response);
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 文字コードの設定
		response.setContentType("text/html; charset=UTF-8");
		request.setCharacterEncoding("UTF-8");
		
		int id = Integer.parseInt(request.getParameter("product_id"));
		String product_name = request.getParameter("product_name");
		String category = request.getParameter("category");
		String explanation = request.getParameter("explanation");
		String quantityStr = request.getParameter("quantity"); 
//		intに型変換
		int quantity = Integer.parseInt(quantityStr);
		Update sql = new Update();
		
		sql.product_update(product_name, category, explanation, quantity, id);
		
//		管理者セッションを取得
		HttpSession session = request.getSession(true);
		Admin admin = (Admin) session.getAttribute("admin");
		
		Login login = new Login();
		
		List<Product> product = null;
		
		product = login.getProductInfo(String.valueOf(admin.getId()));
		
		request.setAttribute("product", product);
		
		RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/product_list.jsp");
		dispatcher.forward(request, response);
		
	}

}

```

・SearchProductServlet.javaクラス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/08ff65e2-8715-34a7-f456-295911c45914.png)

Product_list.jspの検索formタグに/SearchProductServlet・method=”get”と書き、検索ボタンを押したときに、SearchProductServletに飛び、getリクエストなので、dogetメソッドの処理を実行する。
・doGetメソッド
①	フォームに入力された商品名の取得：
request.getparameter(“productName”)を使用し、フォームに入力された名前を取得する。
②	検索条件の判定：
if文の中にproductNameがnullでない、かつ空白のみの文字列でない場合にのみ、検索処理の実行を行っている。
③	商品情報の検索処理：
Searchクラスのインスタンスを生成し、product_searchメソッドを呼び出し、検索を実行している。product_searchメソッドは商品名に一致する商品情報をデータベースから取得し、メソッドから返ってきたものをList<Product>に格納している。
④	検索結果をリクエストスコープに格納：
setAttributeメソッドで、検索結果が格納されたList<Product>をproduct_detailsのリクエストスコープに保存する。

⑤	検索結果を格納した後、RequestDispatcherを使って、リクエストとレスポンスをproduct_search.jspに渡す。検索の処理が完了すると、ブラウザには、product_search.jspによるHTMLが返される。フォワード先のproduct_search.jspで、リクエストスコープからproduct_detailsを取り出し、検索結果を表示する。

```Java
package servlet;

import java.io.IOException;
import java.util.List;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import object.Product;
import sql.Search;


@WebServlet("/SearchProductServlet")
public class SearchProductServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

//	検索の情報を取得し、jspへ送る
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//		フォームから送られた名前を取得する
		String productName = request.getParameter("productName");
		
//		名前が空でない場合のみ検索
		if (productName != null && !productName.trim().isEmpty()) {
			Search search = new Search();
			List<Product> product_details = search.product_search(productName);
			
//			検索結果をリクエストスコープに格納
			request.setAttribute("product_details", product_details);
		}
		
		RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/product_search.jsp");
		dispatcher.forward(request, response);
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

}

```

サーブレットと他クラスとJSPの関係性のイメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/d85b1c80-c312-3575-4cb1-68a9201a311c.png)

・SomeDeleteServlet.javaクラス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/c7286f5c-1542-97b3-201c-1dd1660f9569.png)

まとめて削除ボタンを押したら、SomeDeleteServletへ飛び、削除処理を実行するように設定している。
・doPostメソッド
①	・削除対象の商品IDを取得：
Product_list.jspのチェックボックスのname=”productIds”にする。
jspから送信された商品ID(productIds)をgetParameterValuesで配列として取得する。
・削除対象が選択されていない場合：
チェックリストが一つも選択されていない時、エラーメッセージをリクエストスコープに格納し、最初のproduct_list.jspに遷移する。
②	削除処理の実行：
SomeDeleteProductクラスのproductsome_deleteメソッドを呼び出し、削除処理を実行する。Productsome_deleteメソッドは、渡された商品IDをもとにデータベースの削除処理を行うメソッドである。
③	管理者のセッションの取得：
現在の管理者情報をセッションスコープから取得する。Adminオブジェクトには、管理者IDやその他の情報が格納されている。これは、削除処理が完了した後、最新の商品情報を表示するために、管理者に関連付けられた商品情報を取得するために管理者のセッション情報の取得を行う必要がある。
④	削除後の商品リストを再取得：
Loginクラスのインスタンスを生成し、getProductInfoメソッドを使用して、削除後の最新の商品リストをデータベースから取得する。
⑤	リクエストスコープへ再設定：
再取得した商品リストをproductリクエストスコープに格納する。最新の商品リストを表示するため、product_list.jspに遷移する。product_list.jspにgetAttributeで、リクエストスコープに格納された商品情報を取得してブラウザに表示する。

```Java
package servlet;

import java.io.IOException;
import java.util.List;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import object.Admin;
import object.Product;
import sql.Login;
import sql.SomeDeleteProduct;

@WebServlet("/SomeDeleteServlet")
public class SomeDeleteServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 文字コードの設定
        response.setContentType("text/html; charset=UTF-8");
        request.setCharacterEncoding("UTF-8");
        
//        削除対象の顧客IDをリクエストから取得
        String[] productIds = request.getParameterValues("productIds");
        
        if (productIds == null || productIds.length == 0) {
        	request.setAttribute("error", "削除対象の商品を選択してください");
        	RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/product_list.jsp");
        	dispatcher.forward(request, response);
        	
        }
//        削除処理を実行
        SomeDeleteProduct somedelete = new SomeDeleteProduct();
        somedelete.productsome_delete(productIds);
        
//        管理者のセッションを取得
        HttpSession session = request.getSession(true);
        Admin admin = (Admin) session.getAttribute("admin");
        
//        商品情報を再取得
        Login login = new Login();
        List<Product> product = null;
        
        product = login.getProductInfo(String.valueOf(admin.getId()));
        
//        再取得した顧客情報をリクエストスコープにセット
        request.setAttribute("product", product);
        
//        顧客リスト画面へ遷移
        RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/product_list.jsp");
        dispatcher.forward(request, response);
	}

}

```

サーブレットと他クラスとJSPの関係性のイメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/c8e5fa3b-7e08-1c22-6826-67acdd126093.png)


・UserServlet.javaクラス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/721ca853-92f5-0898-48e7-3ffe7310ee9e.png)

・doGetメソッド
①	First.htmlの「ユーザーでログイン」ボタンを押すと、UserServletにGETリクエストが送信される。このリクエストをUserServletのdoGetメソッドが受け取られる。
②	ログイン画面への転送：
サーバー側でリクエストを処理し、RequestDispatcherを使ってuserlogin.jspに転送する。転送されたuserlogin.jspがブラウザに表示され、ユーザーログイン画面に入力を行える。

・doPostメソッド
①	フォームデータの取得：
getParameter()を使ってuser_id、password、admin_idの情報を取得する。
②	ユーザー認証の実行：
UserLoginクラスのcheck_userメソッドを呼び出して、データベースのuser_tb内のユーザーIDとパスワードの照合を行う。照合が成功すると、setLogin_flag()をtrueにする。そして、UserServletのgetLogin_flag()のtrueを取得して、if文内の処理を実行する。
③	・ログイン成功時の処理：
成功した時、セッションにuser情報を格納する。次に、admin_idが存在するかを確認する。管理者IDがない場合は、エラーメッセージを設定してログイン画面に戻る。
　　・ログイン失敗の処理：
　　認証に失敗した場合、エラーメッセージを設定し、再度ログイン画面に戻す。

```Java
package servlet;

import java.io.IOException;
import java.util.List;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import object.Product;
import object.User;
import sql.UserLogin;

@WebServlet("/UserServlet")
public class UserServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/userlogin.jsp");
		dispatcher.forward(request, response);
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 文字コードの設定
		response.setContentType("text/html; charset=UTF-8");
		request.setCharacterEncoding("UTF-8");
				
        //ログイン画面で入力された値を取得
		String user_id = request.getParameter("user_id");
		String password = request.getParameter("password");
		String admin_id = request.getParameter("admin_id");
		
		UserLogin logins = new UserLogin();
		User user = logins.check_user(user_id, password);
		
		
		
		if (user.getLogin_flag()) {
			System.out.println("ユーザーでログイン成功");
			
			HttpSession user_session = request.getSession(true);
			user_session.setAttribute("user", user);
			
			
			boolean adminExists = logins.checkAdminExist(admin_id);
			if (!adminExists) {
				request.setAttribute("userError", "ユーザーID または パスワード または 管理者IDが存在しません");
				RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/userlogin.jsp");
                dispatcher.forward(request, response);
                return;
			}
		
			List<Product> product = logins.getuserProductInfo(admin_id);
			

			request.setAttribute("product", product);
			
			RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/userproduct_list.jsp");
	        dispatcher.forward(request, response);
			
		} else {
         //	ログイン失敗 エラーを表示
			System.out.println("ユーザログイン失敗");
			boolean adminExists = logins.checkAdminExist(admin_id);
			if (!adminExists) {
				request.setAttribute("userError", "ユーザーID または パスワード または 管理者IDが存在しません");
			}
			RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/userlogin.jsp");
			dispatcher.forward(request, response);
		}
	}

}

```


サーブレットと他クラスとJSPの関係性のイメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3825496/fac73b3e-0fd1-ece3-6c8e-a6ff81c264d3.png)

<h1>参考にしたもの</h1>
【有料級】【総集編】【JavaWebアプリ入門】１本でＷｅｂアプリの基本マスター【初心者～初級者向け】(サーブレット・JSP・ＭＶＣモデル・Tomcat・eclipse・HTML・CSS)

https://www.youtube.com/watch?v=Eeyt08L-wGY

https://skill-for-it.com/java_webapp_2/

https://skill-for-it.com/java_webapp_3/

https://skill-for-it.com/java_webapp_4/

https://skill-for-it.com/java_webapp_5/

https://skill-for-it.com/java_webapp_6/