第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]

JavaBeansの規約

  1. デフォルトコンストラクタ: 引数なしのpublicコンストラクタを持つ
  2. プロパティのカプセル化: フィールドはprivateで宣言
  3. アクセサメソッド: getter/setterメソッドによるプロパティアクセス
  4. Serializable実装: シリアル化可能(推奨)
  5. 命名規約: 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>&lt;jsp:useBean&gt;</code></td>
            <td>JavaBeansインスタンス作成</td>
            <td>id="user", class="...", scope="request"</td>
        </tr>
        <tr>
            <td><code>&lt;jsp:setProperty&gt;</code></td>
            <td>プロパティ値の設定</td>
            <td>property="*" で全パラメータを自動設定</td>
        </tr>
        <tr>
            <td><code>&lt;jsp:getProperty&gt;</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[設定情報、カウンタ]

各スコープの特徴と使用場面

スコープ 生存期間 共有範囲 適用場面
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カウンタ:全ユーザー共通で増加
理解度確認クイズ
  1. JavaBeansの規約について
    有効なJavaBeansクラスが満たすべき5つの規約を挙げてください。
  2. getter/setterメソッドの命名
    「userName」というプロパティに対する適切なgetter/setterメソッド名を答えてください。
  3. JSP標準タグの使い分け
    以下の場面で使用すべきJSPタグはどれですか?
    • JavaBeansのインスタンスを作成したい
    • フォームから送信された全パラメータを一度に設定したい
    • JavaBeansのプロパティをHTML上に表示したい
  4. スコープの選択
    以下の機能を実装する際、どのスコープが適切か理由とともに答えてください:
    • ログインユーザー情報の保持
    • フォーム入力エラーメッセージの表示
    • サイト全体のアクセス数カウンタ
  5. JavaBeansの利点
    JSPでスクリプトレットを直接使う場合と比較した、JavaBeansを使用する利点を3つ挙げてください。

6.5 まとめ

この章では、JavaBeansとJSPの連携について詳しく学習しました。

重要なポイント
  • JavaBeansの概念: データ管理とビジネスロジックの分離
  • 規約の遵守: デフォルトコンストラクタ、getter/setter、カプセル化
  • JSPタグの活用: useBean、setProperty、getPropertyによる操作
  • スコープ管理: page、request、session、applicationの適切な使い分け
  • 保守性の向上: コードの再利用性と可読性の改善