JavaWebリスナー詳解:イベント駆動型プログラミングの実装

はじめに:静的初期化ブロックの役割

package com.example.webapp.servlet;

/**
 * @author Developer
 * @date 2023/8/8
 * description: 静的初期化ブロックの例示
 */
public class InitializationDemo {
    // 静的初期化ブロックはクラスロード時に一度だけ実行される
    // クラスロードという特定のタイミングでコードを実行するための仕組み
    
    static {
        System.out.println("クラスがロードされました。");
    }

    public static void main(String[] args) {
        // メイン処理
    }
}

リスナーは、この静的初期化ブロックと似た概念で、特定のタイミングで処理を実行するための仕組みです。

リスナーとは

  • リスナーはServlet仕様の一部であり、フィルターと同様にServletコンテナによって管理されるコンポーネントです
  • すべてのリスナーインターフェースは「Listener」という接尾辞で終わります

リスナーの目的

  • リスナーはServlet仕様が開発者に提供する特殊なイベント処理のタイミングです
  • 特定のイベント発生時に特定の処理を実行したい場合に、対応するリスナーを実装します

Servlet仕様が提供するリスナー一覧

jakarta.servletパッケージ:

  • ServletContextListener
  • ServletContextAttributeListener
  • ServletRequestListener
  • ServletRequestAttributeListener

jakarta.servlet.httpパッケージ:

  • HttpSessionListener
  • HttpSessionAttributeListener(@WebListener注釈が必要)
  • HttpSessionBindingListener(@WebListener注釈が不要)
  • HttpSessionIdListener
  • HttpSessionActivationListener

リスナーの実装手順:ServletContextListenerを例に

ステップ1:リスナークラスの作成

package com.example.webapp.listener;

import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;

public class AppContextListener implements ServletContextListener {
    
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // アプリケーション起動時に実行される処理
        System.out.println("Webアプリケーションが起動しました。");
        
        // アプリケーション初期化処理
        sce.getServletContext().setAttribute("initTime", System.currentTimeMillis());
    }
    
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // アプリケーション終了時に実行される処理
        System.out.println("Webアプリケーションが終了しました。");
        
        // クリーンアップ処理
    }
}

ステップ2:web.xmlまたはアノテーションでの登録

<listener>
    <listener-class>com.example.webapp.listener.AppContextListener</listener-class>
</listener>

またはアノテーションを使用:

@WebListener
public class AppContextListener implements ServletContextListener {
    // 実装
}

実践例:リアルタイムオンラインユーザー数の表示

要件:ログイン中のユーザー数をリアルタイムで表示する機能を実装

実装方針:Userオブジェクトがセッションにバインド・アンバインドされるタイミングを監視

ステップ1:UserクラスにHttpSessionBindingListenerを実装

package com.example.webapp.model;

import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSessionBindingEvent;
import jakarta.servlet.http.HttpSessionBindingListener;

public class UserProfile implements HttpSessionBindingListener {
    private String userId;
    private String displayName;
    
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        // ユーザーがログインした時の処理
        ServletContext appContext = event.getSession().getServletContext();
        
        Integer activeUsers = (Integer) appContext.getAttribute("activeUsers");
        if (activeUsers == null) {
            appContext.setAttribute("activeUsers", 1);
        } else {
            appContext.setAttribute("activeUsers", activeUsers + 1);
        }
    }
    
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        // ユーザーがログアウトした時の処理
        ServletContext appContext = event.getSession().getServletContext();
        Integer activeUsers = (Integer) appContext.getAttribute("activeUsers");
        
        if (activeUsers != null && activeUsers > 0) {
            appContext.setAttribute("activeUsers", activeUsers - 1);
        }
    }
    
    // コンストラクタ、ゲッター、セッター
    public UserProfile() {}
    
    public UserProfile(String userId, String displayName) {
        this.userId = userId;
        this.displayName = displayName;
    }
    
    public String getUserId() {
        return userId;
    }
    
    public void setUserId(String userId) {
        this.userId = userId;
    }
    
    public String getDisplayName() {
        return displayName;
    }
    
    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }
}

ステップ2:ログイン・ログアウト処理の修正

ログイン処理:

// 認証成功後
UserProfile userProfile = new UserProfile(username, userDisplayName);
session.setAttribute("currentUser", userProfile);

ログアウト処理:

HttpSession currentSession = request.getSession(false);
if (currentSession != null) {
    // ユーザーオブジェクトをセッションから削除
    currentSession.removeAttribute("currentUser");
    
    // セッションを無効化
    currentSession.invalidate();
}

ステップ3:JSPでの表示

<div class="user-info">
    <h2>ようこそ ${currentUser.displayName} さん</h2>
    <p>現在のオンラインユーザー数:<span class="highlight">${activeUsers}</span>人</p>
</div>

リスナーの実行タイミング

すべてのリスナーメソッドは開発者が直接呼び出すのではなく、Webコンテナによって特定のイベント発生時に自動的に呼び出されます。

例:

  • ServletContextListener:アプリケーションの起動・停止時
  • HttpSessionListener:セッションの作成・破棄時
  • HttpSessionBindingListener:オブジェクトのセッションへのバインド・アンバインド時

タグ: JavaWeb Servlet Listener HttpSession ServletContext

7月9日 00:05 投稿