第6章: JSPとJavaBeans
JavaBeansによるデータ管理とJSPの連携
この章で学ぶこと
- JavaBeansの基本概念と設計パターンの理解
- プロパティとアクセサメソッド(getter/setter)の実装
- JavaBeansの作成方法とベストプラクティス
- JSPでのJavaBeansの利用方法(jsp:useBeanタグなど)
- データの受け渡しとスコープ管理の実践的活用
6.1 JavaBeansとは何か
JavaBeansは、Javaで開発されたソフトウェアコンポーネントの標準仕様です。特定の規約に従って作成されたJavaクラスのことで、データの格納、操作、および他のコンポーネント間でのデータ受け渡しを担います。
flowchart TD
A[JavaBeans] --> B[データ格納
(プロパティ)] A --> C[データアクセス
(getter/setter)] A --> D[シリアル化対応
(Serializable)] B --> E[フィールド変数
(private修飾子)] C --> F[getXxx()
setXxx()] D --> G[データの永続化
セッション保存] A --> H[JSP連携] H --> I[jsp:useBean] H --> J[jsp:setProperty] H --> K[jsp:getProperty]
(プロパティ)] A --> C[データアクセス
(getter/setter)] A --> D[シリアル化対応
(Serializable)] B --> E[フィールド変数
(private修飾子)] C --> F[getXxx()
setXxx()] D --> G[データの永続化
セッション保存] A --> H[JSP連携] H --> I[jsp:useBean] H --> J[jsp:setProperty] H --> K[jsp:getProperty]
JavaBeansの規約
- デフォルトコンストラクタ: 引数なしのpublicコンストラクタを持つ
- プロパティのカプセル化: フィールドはprivateで宣言
- アクセサメソッド: getter/setterメソッドによるプロパティアクセス
- Serializable実装: シリアル化可能(推奨)
- 命名規約: getPropertyName()、setPropertyName()の形式
JavaBeansの利点
- 再利用性: 他のプロジェクトでも使用可能な汎用コンポーネント
- 保守性: データ構造の変更が他の部分に与える影響を最小限に抑制
- 可読性: コードの構造が明確で理解しやすい
- デバッグの容易さ: データの状態を簡単に確認・変更可能
- JSP統合: JSPの標準タグで簡単に操作可能
6.2 JavaBeansクラスの実装
具体的なJavaBeansクラスを作成し、プロパティとアクセサメソッドの実装方法を学習します。
実習 6-1: ユーザー情報を管理するJavaBeansの作成
ユーザーの基本情報を管理するUser JavaBeansクラスを作成します。
手順1: User.javaクラスの作成
package com.example.beans;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.Period;
/**
* ユーザー情報を管理するJavaBeansクラス
* JavaBeansの規約に従って実装
*/
public class User implements Serializable {
// serialVersionUID(Serializable実装時に推奨)
private static final long serialVersionUID = 1L;
// プライベートフィールド(プロパティ)
private String username;
private String email;
private int age;
private LocalDate birthDate;
private String address;
private String phoneNumber;
// デフォルトコンストラクタ(必須)
public User() {
// 初期化処理が必要な場合はここに記述
}
// コンストラクタ(オプション - 便利メソッドとして提供)
public User(String username, String email, int age) {
this.username = username;
this.email = email;
this.age = age;
}
// getter/setterメソッド
/**
* ユーザー名を取得
* @return username ユーザー名
*/
public String getUsername() {
return username;
}
/**
* ユーザー名を設定
* @param username 設定するユーザー名
*/
public void setUsername(String username) {
this.username = username;
}
/**
* メールアドレスを取得
* @return email メールアドレス
*/
public String getEmail() {
return email;
}
/**
* メールアドレスを設定
* @param email 設定するメールアドレス
*/
public void setEmail(String email) {
this.email = email;
}
/**
* 年齢を取得
* @return age 年齢
*/
public int getAge() {
return age;
}
/**
* 年齢を設定
* @param age 設定する年齢
*/
public void setAge(int age) {
this.age = age;
}
/**
* 生年月日を取得
* @return birthDate 生年月日
*/
public LocalDate getBirthDate() {
return birthDate;
}
/**
* 生年月日を設定
* @param birthDate 設定する生年月日
*/
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
// 生年月日から年齢を自動計算
if (birthDate != null) {
this.age = Period.between(birthDate, LocalDate.now()).getYears();
}
}
/**
* 住所を取得
* @return address 住所
*/
public String getAddress() {
return address;
}
/**
* 住所を設定
* @param address 設定する住所
*/
public void setAddress(String address) {
this.address = address;
}
/**
* 電話番号を取得
* @return phoneNumber 電話番号
*/
public String getPhoneNumber() {
return phoneNumber;
}
/**
* 電話番号を設定
* @param phoneNumber 設定する電話番号
*/
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
// ビジネスロジック用メソッド(JavaBeansでも独自メソッドを定義可能)
/**
* ユーザーが成人かどうかを判定
* @return 成人の場合true、未成年の場合false
*/
public boolean isAdult() {
return age >= 20;
}
/**
* メールアドレスの形式をチェック
* @return 正しい形式の場合true、不正な場合false
*/
public boolean isValidEmail() {
if (email == null || email.isEmpty()) {
return false;
}
// 簡易的なメール形式チェック
return email.contains("@") && email.contains(".");
}
/**
* ユーザー情報の文字列表現
* @return ユーザー情報を表す文字列
*/
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", email='" + email + '\'' +
", age=" + age +
", birthDate=" + birthDate +
", address='" + address + '\'' +
", phoneNumber='" + phoneNumber + '\'' +
'}';
}
}
手順2: JavaBeansをテストするJSPページ(testUser.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="com.example.beans.User, java.time.LocalDate" %>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>JavaBeans テスト</title>
</head>
<body>
<h2>JavaBeans(User)の動作テスト</h2>
<%
// JavaBeansのインスタンス作成
User user = new User();
// プロパティの設定
user.setUsername("田中太郎");
user.setEmail("tanaka@example.com");
user.setAge(25);
user.setBirthDate(LocalDate.of(1999, 5, 15));
user.setAddress("東京都渋谷区");
user.setPhoneNumber("090-1234-5678");
// ページスコープに保存(後でJSPタグから利用可能)
pageContext.setAttribute("userBean", user);
%>
<h3>1. 直接メソッド呼び出しによるプロパティ取得</h3>
<table border="1" cellpadding="5">
<tr>
<th>プロパティ</th>
<th>値</th>
<th>取得方法</th>
</tr>
<tr>
<td>ユーザー名</td>
<td><%= user.getUsername() %></td>
<td>getUsername()メソッド</td>
</tr>
<tr>
<td>メールアドレス</td>
<td><%= user.getEmail() %></td>
<td>getEmail()メソッド</td>
</tr>
<tr>
<td>年齢</td>
<td><%= user.getAge() %>歳</td>
<td>getAge()メソッド</td>
</tr>
<tr>
<td>生年月日</td>
<td><%= user.getBirthDate() %></td>
<td>getBirthDate()メソッド</td>
</tr>
<tr>
<td>住所</td>
<td><%= user.getAddress() %></td>
<td>getAddress()メソッド</td>
</tr>
<tr>
<td>電話番号</td>
<td><%= user.getPhoneNumber() %></td>
<td>getPhoneNumber()メソッド</td>
</tr>
</table>
<h3>2. ビジネスロジックメソッドの実行</h3>
<ul>
<li>成人判定: <%= user.isAdult() ? "成人" : "未成年" %></li>
<li>メール形式チェック: <%= user.isValidEmail() ? "正しい形式" : "不正な形式" %></li>
<li>toString(): <%= user.toString() %></li>
</ul>
<h3>3. JavaBeansの動的な値変更</h3>
<%
// 値を動的に変更
user.setAge(17); // 未成年に変更
user.setEmail("invalid-email"); // 不正なメール形式に変更
%>
<p>年齢を17歳、メールを不正な形式に変更後:</p>
<ul>
<li>年齢: <%= user.getAge() %>歳</li>
<li>成人判定: <%= user.isAdult() ? "成人" : "未成年" %></li>
<li>メール: <%= user.getEmail() %></li>
<li>メール形式チェック: <%= user.isValidEmail() ? "正しい形式" : "不正な形式" %></li>
</ul>
</body>
</html>
期待される結果
JavaBeansのプロパティが正しく設定・取得され、ビジネスロジックメソッドが適切に動作することを確認できます。
6.3 JSP標準タグによるJavaBeansの操作
JSPでは、JavaBeansを操作するための専用タグ(jsp:useBean、jsp:setProperty、jsp:getProperty)が提供されており、スクリプトレットを使用せずにJavaBeansを活用できます。
JSP JavaBeansタグの概要
タグ | 用途 | 主な属性 |
---|---|---|
<jsp:useBean> |
JavaBeansのインスタンス作成・取得 | id, class, scope |
<jsp:setProperty> |
JavaBeansのプロパティ設定 | name, property, value, param |
<jsp:getProperty> |
JavaBeansのプロパティ取得・出力 | name, property |
実習 6-2: JSPタグを使用したJavaBeansの操作
JSP標準タグを使用してJavaBeansを操作し、フォームデータとの連携を実装します。
手順1: ユーザー登録フォーム(registerForm.html)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ユーザー登録フォーム</title>
<style>
.form-container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, textarea, select {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
background-color: #f57c00;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="form-container">
<h2>ユーザー登録</h2>
<form action="registerUser.jsp" method="post">
<div class="form-group">
<label for="username">ユーザー名(必須):</label>
<input type="text" id="username" name="username" required>
</div>
<div class="form-group">
<label for="email">メールアドレス(必須):</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="age">年齢:</label>
<input type="number" id="age" name="age" min="0" max="150">
</div>
<div class="form-group">
<label for="address">住所:</label>
<textarea id="address" name="address" rows="3"></textarea>
</div>
<div class="form-group">
<label for="phoneNumber">電話番号:</label>
<input type="tel" id="phoneNumber" name="phoneNumber">
</div>
<div class="form-group">
<button type="submit">登録</button>
<button type="reset">リセット</button>
</div>
</form>
</div>
</body>
</html>
手順2: JSPタグによるJavaBeansの活用(registerUser.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ユーザー登録結果</title>
</head>
<body>
<h2>ユーザー登録結果</h2>
<%-- JavaBeansのインスタンス作成・取得 --%>
<jsp:useBean id="user" class="com.example.beans.User" scope="request" />
<%-- リクエストパラメータから自動的にプロパティを設定 --%>
<jsp:setProperty name="user" property="*" />
<%-- 個別のプロパティ設定も可能 --%>
<jsp:setProperty name="user" property="username" param="username" />
<h3>登録されたユーザー情報</h3>
<table border="1" cellpadding="10">
<tr>
<th>項目</th>
<th>値</th>
</tr>
<tr>
<td>ユーザー名</td>
<td><jsp:getProperty name="user" property="username" /></td>
</tr>
<tr>
<td>メールアドレス</td>
<td><jsp:getProperty name="user" property="email" /></td>
</tr>
<tr>
<td>年齢</td>
<td><jsp:getProperty name="user" property="age" />歳</td>
</tr>
<tr>
<td>住所</td>
<td><jsp:getProperty name="user" property="address" /></td>
</tr>
<tr>
<td>電話番号</td>
<td><jsp:getProperty name="user" property="phoneNumber" /></td>
</tr>
</table>
<h3>検証結果</h3>
<%-- ビジネスロジックメソッドの呼び出しはスクリプトレットで --%>
<%
// JavaBeansインスタンスを取得
com.example.beans.User userBean = (com.example.beans.User) request.getAttribute("user");
if (userBean != null) {
%>
<ul>
<li>成人判定: <%= userBean.isAdult() ? "成人" : "未成年" %></li>
<li>メール形式: <%= userBean.isValidEmail() ? "正しい形式" : "不正な形式" %></li>
</ul>
<%
}
%>
<%-- 条件による表示の切り替え --%>
<%
if (userBean != null && userBean.isValidEmail()) {
%>
<div style="background-color: #e8f5e8; padding: 15px; border: 1px solid #4caf50; border-radius: 5px;">
<h4>✅ 登録完了</h4>
<p>ユーザー情報が正常に登録されました。</p>
</div>
<%
} else {
%>
<div style="background-color: #ffebee; padding: 15px; border: 1px solid #f44336; border-radius: 5px;">
<h4>❌ 登録エラー</h4>
<p>メールアドレスの形式が正しくありません。再度入力してください。</p>
</div>
<%
}
%>
<h3>JSPタグの説明</h3>
<table border="1" cellpadding="5">
<tr>
<th>使用したタグ</th>
<th>機能</th>
<th>属性説明</th>
</tr>
<tr>
<td><code><jsp:useBean></code></td>
<td>JavaBeansインスタンス作成</td>
<td>id="user", class="...", scope="request"</td>
</tr>
<tr>
<td><code><jsp:setProperty></code></td>
<td>プロパティ値の設定</td>
<td>property="*" で全パラメータを自動設定</td>
</tr>
<tr>
<td><code><jsp:getProperty></code></td>
<td>プロパティ値の取得・表示</td>
<td>name="user", property="プロパティ名"</td>
</tr>
</table>
<p><a href="registerForm.html">新しいユーザーを登録</a></p>
</body>
</html>
期待される結果
フォームで入力したデータがJavaBeansに自動的に設定され、JSPタグで表示されます。メール形式のバリデーション結果も確認できます。
6.4 スコープによるJavaBeansの管理
JavaBeansは異なるスコープ(page、request、session、application)で管理でき、データの有効範囲と生存期間を制御できます。
flowchart TD
A[JavaBeansスコープ] --> B[pageスコープ]
A --> C[requestスコープ]
A --> D[sessionスコープ]
A --> E[applicationスコープ]
B --> F["現在のページ内のみ
(最短の生存期間)"] C --> G["リクエスト処理期間中
(forward先でも有効)"] D --> H["セッション終了まで
(ユーザー固有データ)"] E --> I["アプリケーション終了まで
(全ユーザー共有)"] B --> J[一時的な処理] C --> K[画面間データ受け渡し] D --> L[ログイン情報、買い物カート] E --> M[設定情報、カウンタ]
(最短の生存期間)"] C --> G["リクエスト処理期間中
(forward先でも有効)"] D --> H["セッション終了まで
(ユーザー固有データ)"] E --> I["アプリケーション終了まで
(全ユーザー共有)"] B --> J[一時的な処理] C --> K[画面間データ受け渡し] D --> L[ログイン情報、買い物カート] E --> M[設定情報、カウンタ]
各スコープの特徴と使用場面
スコープ | 生存期間 | 共有範囲 | 適用場面 |
---|---|---|---|
page | 現在のページ処理中 | 現在のページのみ | 一時的な計算結果、ページ内での変数 |
request | リクエスト処理中 | forward先のページまで | フォーム処理結果、エラーメッセージ |
session | セッション終了まで | 同一ユーザーのすべてのページ | ログイン情報、買い物カート、設定 |
application | アプリケーション終了まで | すべてのユーザー | アクセス数カウンタ、設定情報 |
実習 6-3: スコープ別JavaBeansの動作確認
異なるスコープでJavaBeansを管理し、データの生存期間と共有範囲を確認します。
手順1: カウンター機能JavaBeans(Counter.java)
package com.example.beans;
import java.io.Serializable;
/**
* カウンター機能を提供するJavaBeansクラス
* 異なるスコープでの動作確認に使用
*/
public class Counter implements Serializable {
private static final long serialVersionUID = 1L;
// カウンタ値
private int count;
// カウンタ名(識別用)
private String name;
// デフォルトコンストラクタ
public Counter() {
this.count = 0;
this.name = "デフォルトカウンタ";
}
// コンストラクタ
public Counter(String name) {
this.count = 0;
this.name = name;
}
// getter/setter
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// カウンタをインクリメント
public void increment() {
count++;
}
// カウンタをリセット
public void reset() {
count = 0;
}
@Override
public String toString() {
return name + ": " + count;
}
}
手順2: スコープテスト用JSP(scopeTest.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>JavaBeansスコープテスト</title>
</head>
<body>
<h2>JavaBeansスコープ別動作テスト</h2>
<%-- pageスコープのJavaBeans --%>
<jsp:useBean id="pageCounter" class="com.example.beans.Counter" scope="page" />
<jsp:setProperty name="pageCounter" property="name" value="ページスコープカウンタ" />
<%-- requestスコープのJavaBeans --%>
<jsp:useBean id="requestCounter" class="com.example.beans.Counter" scope="request" />
<jsp:setProperty name="requestCounter" property="name" value="リクエストスコープカウンタ" />
<%-- sessionスコープのJavaBeans --%>
<jsp:useBean id="sessionCounter" class="com.example.beans.Counter" scope="session" />
<jsp:setProperty name="sessionCounter" property="name" value="セッションスコープカウンタ" />
<%-- applicationスコープのJavaBeans --%>
<jsp:useBean id="appCounter" class="com.example.beans.Counter" scope="application" />
<jsp:setProperty name="appCounter" property="name" value="アプリケーションスコープカウンタ" />
<%-- 各カウンタをインクリメント --%>
<%
// JavaBeansインスタンスを取得してインクリメント
com.example.beans.Counter pc = (com.example.beans.Counter) pageContext.getAttribute("pageCounter");
com.example.beans.Counter rc = (com.example.beans.Counter) request.getAttribute("requestCounter");
com.example.beans.Counter sc = (com.example.beans.Counter) session.getAttribute("sessionCounter");
com.example.beans.Counter ac = (com.example.beans.Counter) application.getAttribute("appCounter");
pc.increment();
rc.increment();
sc.increment();
ac.increment();
%>
<h3>現在のカウンタ値</h3>
<table border="1" cellpadding="10">
<tr>
<th>スコープ</th>
<th>カウンタ名</th>
<th>現在値</th>
<th>説明</th>
</tr>
<tr>
<td>page</td>
<td><jsp:getProperty name="pageCounter" property="name" /></td>
<td><jsp:getProperty name="pageCounter" property="count" /></td>
<td>ページリロードごとに1にリセット</td>
</tr>
<tr>
<td>request</td>
<td><jsp:getProperty name="requestCounter" property="name" /></td>
<td><jsp:getProperty name="requestCounter" property="count" /></td>
<td>リクエストごとに1にリセット</td>
</tr>
<tr>
<td>session</td>
<td><jsp:getProperty name="sessionCounter" property="name" /></td>
<td><jsp:getProperty name="sessionCounter" property="count" /></td>
<td>ユーザーごとに増加(ブラウザ閉じるまで)</td>
</tr>
<tr>
<td>application</td>
<td><jsp:getProperty name="appCounter" property="name" /></td>
<td><jsp:getProperty name="appCounter" property="count" /></td>
<td>全ユーザー共通で増加(サーバー再起動まで)</td>
</tr>
</table>
<h3>操作</h3>
<ul>
<li><a href="scopeTest.jsp">ページをリロード</a> - session/applicationカウンタは増加</li>
<li><a href="scopeTest.jsp" target="_blank">新しいタブで開く</a> - sessionは同じ、applicationは全体で共有</li>
</ul>
<h3>セッション情報</h3>
<p>セッションID: <%= session.getId() %></p>
<p>セッション作成時刻: <%= new java.util.Date(session.getCreationTime()) %></p>
<p>最終アクセス時刻: <%= new java.util.Date(session.getLastAccessedTime()) %></p>
<form action="scopeTest.jsp" method="post">
<button type="submit">POST でアクセス</button>
</form>
</body>
</html>
期待される結果
- pageカウンタ:常に1(ページごとにリセット)
- requestカウンタ:常に1(リクエストごとにリセット)
- sessionカウンタ:同一セッション内で増加
- applicationカウンタ:全ユーザー共通で増加
理解度確認クイズ
-
JavaBeansの規約について
有効なJavaBeansクラスが満たすべき5つの規約を挙げてください。 -
getter/setterメソッドの命名
「userName」というプロパティに対する適切なgetter/setterメソッド名を答えてください。 -
JSP標準タグの使い分け
以下の場面で使用すべきJSPタグはどれですか?- JavaBeansのインスタンスを作成したい
- フォームから送信された全パラメータを一度に設定したい
- JavaBeansのプロパティをHTML上に表示したい
-
スコープの選択
以下の機能を実装する際、どのスコープが適切か理由とともに答えてください:- ログインユーザー情報の保持
- フォーム入力エラーメッセージの表示
- サイト全体のアクセス数カウンタ
-
JavaBeansの利点
JSPでスクリプトレットを直接使う場合と比較した、JavaBeansを使用する利点を3つ挙げてください。
6.5 まとめ
この章では、JavaBeansとJSPの連携について詳しく学習しました。
重要なポイント
- JavaBeansの概念: データ管理とビジネスロジックの分離
- 規約の遵守: デフォルトコンストラクタ、getter/setter、カプセル化
- JSPタグの活用: useBean、setProperty、getPropertyによる操作
- スコープ管理: page、request、session、applicationの適切な使い分け
- 保守性の向上: コードの再利用性と可読性の改善