本記事では、Struts2ベースのWebアプリケーションにおける「セッションとパラメータの使い分け」について、実装例を交えて整理します。
画面遷移を伴うWebアプリケーションにおいて、「どの情報をセッションで保持し、どの情報をパラメータで渡すか」は、設計段階での重要な検討ポイントです。特に複数画面をまたぐ機能や、戻り先制御の実装時には、情報の保持手段がバグやユーザビリティに直結するためです。
✅ 1. なぜ「使い分け」が必要なのか?
例えば、以下のような画面遷移を想定します。
掲示板一覧 → 掲示板詳細 → スレッド詳細 → 投稿
このように「掲示板ID」「スレッドID」「ユーザーID」などが必要なデータは、各画面や処理で異なるライフサイクルを持っています。
データ名 | 使用タイミング | 適切な保持方法 |
---|---|---|
ユーザーID | ログイン後〜ログアウトまで | セッション |
掲示板ID | 掲示板詳細参照時 | URLパラメータ |
スレッドID | スレッド参照・投稿時 | セッション |
投稿内容 | 一時的(フォーム入力) | リクエスト |
このように、「情報のライフサイクル」 に基づいて、保持方法を明確に分けることがポイントです。
✅ 2. セッションを使うべきケース
以下のようなケースではセッションを使うのが適しています。
-
ログイン中のユーザー情報(ユーザーID、権限など)
-
投稿時の投稿時のスレッドID(同一スレッドへの連続投稿など)
-
「戻る」や「キャンセル」時に再表示する対象情報の保持
📌 特に「戻る」や「投稿後に再表示する対象スレッド」は、URLに埋め込むのではなくセッションで持つことで、リダイレクト後も正しく再取得できます。
✅ 3. URLパラメータを使うべきケース
一方で、以下のような情報はURLパラメータとして渡すのが適しています。
-
掲示板ID(掲示板詳細を直接参照するケースが多いため)
-
スレッドID(スレッド詳細リンクなど明示的な遷移時)
📌 URLに情報が見えることで、ユーザーがブックマーク可能、またはSEO対応にもなる利点があります。
📝 4. 実装例(実プロジェクトに即した記述)
✅ PostAction.java 抜粋
投稿処理において、投稿対象の thread_id
はセッションに保持されています。
// セッションから thread_id を取得
Integer threadId = (Integer) session.get("thread_id");
// Postオブジェクトに thread_id を設定
post.setThread_id(threadId);
// 再度 thread_id をセッションに保存(PostListActionへの遷移のため)
session.put("thread_id", threadId);
- 投稿時に thread_id をセッションから取得し、投稿内容と紐づける。
- 画面遷移(例:投稿一覧再取得)後も同じスレッドが対象になるよう、thread_id をセッションに再格納している。
✅ BoardDetailAction.java 抜粋
掲示板ID(board_id)
は、URLパラメータから取得しています。
// URLパラメータから掲示板IDを取得(内部的にServletRequestを使用)
private int getBulletinboardIdFromUrl() {
HttpServletRequest request = ServletActionContext.getRequest();
int id = Integer.parseInt(request.getParameter("id"));
logger.debug("Bulletinboard ID from URL: " + id);
return id;
}
- URLに含まれる id をパースして、掲示板詳細取得・スレッド作成リンク用の処理に使用。
- このIDは、掲示板のスレッド一覧取得や、スレッド作成画面遷移のリンク生成に活用される。
✅ まとめ表
データ名 | 使用箇所 | 取得方法 | 保存対象 |
---|---|---|---|
user_id |
ログイン後各画面共通 | ログイン時セッションに格納 | セッション |
thread_id |
投稿処理 (PostAction ) |
セッションから取得/保存 | セッション |
board_id |
掲示板詳細 (BoardDetailAction ) |
URLパラメータから取得 | URL(明示的) |
✅ 5. 設計ポイントまとめ
-
一時的な操作対象(スレッドなど)はセッションに保持
-
複数ユーザーが閲覧・遷移できるもの(掲示板など)はURLパラメータで渡す
-
「戻る」「キャンセル」などの機能では、セッション上のIDを使って状態復元
このように設計することで、Struts2のリダイレクト・画面遷移に対応した、堅牢なWebアプリが実現できます。
🔍 補足:なぜ「掲示板ID」はURLパラメータで渡すのか?
掲示板ID(board_id)
のような情報を「セッションで持てばいいのでは?」と考えるのは自然な発想です。
実際、thread_id
はセッションで保持しているのだから、統一した方がスッキリするようにも思えます。
しかし、以下のような理由から「掲示板IDはURLパラメータで渡す方が適している」とされています。
✅ 理由①:直接アクセスやブックマークを許容したい場合
掲示板の詳細画面は、ログインユーザーであれば 誰でも見られる情報 です。
そのため、次のような使い方が求められます。
-
URLを直接入力してアクセスできる
-
ブックマークして後から再訪できる
-
他人にURLリンクを共有できる(社内チャット等)
こういった用途をサポートするには、https://example.com/board/detail?id=3
のように、URLにIDが含まれていることが重要です。
一方、セッションで保持する方式では、前の画面を経由しないと正しく動作できません。
✅ 理由②:RESTful設計やWebの基本原則に則る
REST的な観点では、URLは一意なリソースを表現するものとされます。
GET /board/detail?id=3 → 掲示板ID=3の詳細情報
このように明示的なURL設計にすることで:
-
どのリソースを見ているかが明確になる
-
クローラやリンク解析にも有利
-
ブラウザの履歴・戻る機能とも親和性が高い
このため、読み取り専用・共有可能な情報はURLパラメータで渡すのが自然とされています。
✅ 理由③:「IDを見せたくない」場合はどうする?
「URLにIDを出したくない」「内部IDを見せるのがセキュリティ的に心配」というケースもあります。
その場合は、以下のような対策が考えられます。
✅ 方法1:トークンでマスキング
/board/detail?token=abcde12345
-
トークンとIDの対応関係をサーバー側で管理。
-
ユーザーにはIDを見せず、安全なURLでアクセス可能。
✅ 方法2:セッションに保持(ただし注意点あり)
-
前画面でセッションにIDを保存 → 詳細画面で使用。
-
ただし、直接URLを開くことができない・戻る機能と相性が悪いなどの制約があります。
✅ 結論:設計目的に応じて使い分ける
使用ケース | URLパラメータ | セッション保持 |
---|---|---|
リンク共有、直接アクセス、再訪を許可したい | ✅ 向いている | ❌ 不向き |
ログインユーザー専用・一時的な操作対象 | ❌ 不向き | ✅ 向いている |
IDを秘匿したい(セキュリティ的配慮) | トークン方式などで対応 | ✅ 可能 |
このように、「なぜURLパラメータなのか?」という観点を押さえることで、より明確な画面遷移設計ができるようになります。
✨ 補足A:セッションでIDを保持する設計例(実装あり)
✅ 目的
一時的な操作対象(スレッドIDなど)をセッションに保持することで、
画面遷移後も状態を維持し、不要なパラメータの受け渡しを避けることができます。
✅ 使用ケースの一例(※本プロジェクトの設計とは異なる)
- スレッド詳細画面でスレッドIDをセッションに保存し、投稿画面でそのIDを利用
- 投稿完了後、セッションに保持していたIDを使って再表示する
💡 本プロジェクトでは「投稿フォームと投稿一覧」が同一のスレッド詳細画面に統合されています。
本例は、画面分離型の設計パターンにおけるセッション活用例です。
✅ 実装例(PostAction.java)
// セッションからスレッドIDを取得
Integer threadId = (Integer) session.get("thread_id");
// 投稿オブジェクトにスレッドIDをセット
post.setThread_id(threadId);
// 投稿データの保存処理など...
// 投稿完了後、同一スレッドの再表示に備えて再度スレッドIDをセッションに保存
session.put("thread_id", threadId);
✅ 利点と注意点
項目 | 内容 |
---|---|
✅ 利点 | URLがスッキリする/セキュリティ上IDを隠せる/リダイレクトで状態維持可能 |
⚠️ 注意点 | セッションに依存しすぎると、画面の再現性や状態管理が煩雑になる |
✅ 活用のポイント
-
IDをセッションに入れる対象は「一時的に操作するもの」に限定
-
投稿、編集、削除など「ユーザー固有の操作」において有効
-
セッションタイムアウトや多重ログイン時の考慮も必要
✅ 説明補足
- 実装はあくまで「スレッド詳細 → 投稿 → 戻る」のような画面遷移型で使われる典型パターンの例です。
- 本プロジェクトでは、画面遷移せずに同一画面内で完結する設計のため、完全一致ではありません。
- しかし、読者が他のWebアプリ開発でセッション設計に悩んだ際に、参考になる構成となっています。
✨ 補足B:トークン方式でIDをURLから隠す方法(実装あり)
✅ 目的
URLにID(掲示板ID、スレッドIDなど)を表示したくない場合、
ランダムなトークンに変換してやり取りすることで、IDを直接露出せずに遷移を実現できます。
✅ 使用ケースの一例
- 掲示板詳細画面やスレッド詳細画面へのアクセスに「ランダムトークン」を使う
- トークンと実IDの対応表をサーバー側(DBまたはセッション)で管理
💡 URLに
?id=123
のようにIDが表示されることを避けたいときに有効な設計です。
✅ 実装ステップ(簡易例)
🔹 ステップ1:トークンを生成してセッションに保存
// 例:掲示板IDからトークンを生成
String token = UUID.randomUUID().toString();
session.put("token_" + token, bulletinboardId);
// URLにトークンを付与してリンク生成
String url = "boardDetail.action?token=" + token;
🔹 ステップ2:トークンを受け取ってIDに変換
HttpServletRequest request = ServletActionContext.getRequest();
String token = request.getParameter("token");
// セッションから実IDを取得
Integer boardId = (Integer) session.get("token_" + token);
if (boardId == null) {
// 不正アクセス or 有効期限切れの処理
return "error";
}
画面 → トークン生成 → リンク生成 → トークン受信 → ID復元
✅ 利点と注意点
項目 | 内容 |
---|---|
✅ 利点 | IDをURLに表示しない/URLコピー・共有時にも安全性が向上 |
⚠️ 注意点 | トークンの有効期限・管理が必要/セッション肥大化に注意 |
✅ 活用のポイント
-
セキュリティ重視の設計が必要な場面で有効(例:管理機能・内部画面)
-
トークンの有効期限やアクセス権限を必ず検証する
-
トークンをDBに保存する方式も可(ログインユーザー単位で管理)
✅ 応用例
-
パスワード再発行メールでの一時トークンリンク
-
管理画面でのURL保護(内部IDを見せない)
🔍 補足のまとめ
- 補足Aは「セッションにIDを保持」するケース
- 補足Bは「URLにIDを見せずトークンに置き換える」ケース
両者とも、「セキュリティ」や「画面状態の保持」を考慮した設計パターンです。プロジェクトの要件に応じて、適切な方式を選ぶ指針として活用できます。
✨ シリーズまとめ(Vol.11.2.xx アクション層設計)
-
✅ Vol.11.2 UX改善に効く!アクション層設計と入力制御の極意(プロローグ) ― アクション層からはじめるStruts2の“わかりやすい画面遷移”と“操作性向上” ―
-
✅ Vol.11.2.1 アクション層の役割と設計パターン ―「ただのリクエスト受け口」から「ユースケースの橋渡し役」へ―
-
✅ Vol.11.2.2 アクションクラスの3設計スタイルと選定基準 ― 機能粒度・責務分離・保守性のバランスをどう取るか? ―
🧭 関連記事(Vol.11.xxxシリーズ)
連番 | タイトル | 内容分類 |
---|---|---|
Vol.11.0 | Struts2が提供してくれる便利機能まとめ9選 | 導入&概要 |
Vol.11.1 | 自動注入とステートレスActionの仕組み | フレームワーク内部理解 |
Vol.11.2 | UX改善に効く!アクション層設計と入力制御の極意(プロローグ) | UX設計・アクション層総論 |
Vol.11.2.1 | 【実践編】Struts2アクション層の役割と設計パターン(Command型 / UIアクション分離など) | アクション設計パターン |
Vol.11.2.2 | 【UX重視】戻るボタン・キャンセル処理の設計手法と「戻り先管理」のスマート実装 | 戻り先制御とUX設計 |
Vol.11.2.3 | 【設計ノウハウ】多画面遷移時のパラメータ受け渡し・保持戦略(セッション vs hidden vs URL) | パラメータ多重管理 |
Vol.11.2.5 | 【トラブル防止】アクション層の共通処理とメンテナブルなBaseAction設計 | アクション共通化/保守性 |
Vol.11.3 | Struts2の defaultStack とは?Interceptorの中身を詳しく追ってみる | Interceptor |
Vol.11.3.2 | 🔧 Vol.11.3.2 独自Interceptorの作り方と使い所 Struts2のカスタマイズを“実践で使えるレベル”に一歩進めよう | Interceptor |
Vol.11.4 | 入門者のための「パラメータ自動バインディング」完全理解ガイド | 自動バインディング |
Vol.Vol.11.4.1 | 入門者のための自動バインディング実践パターン集 | 自動バインディング |
Vol.11.5 | Struts2の構成理解が“実務レベル”へと進化する決定版 | 設定ファイル構造 |
Vol.11.5.1 | Struts2の“画面遷移の全体像”を理解するためのマイルストーン記事 | 設定ファイル構造 |
Vol.11.6 | ActionSupport の便利メソッドと国際化対応 | ユーティリティ / i18n |
Vol.11.7 | validate() / input 戦略とUX設計 | 開発スタイルの違い |
Vol.11.8 | アノテーションベースの設定 vs XML定義の比較 | 開発スタイルの違い |
Vol.11.9 | バリデーション完全解説(XML / アノテーション) | バリデーション(※Vol.8補完) |
Vol.11.10 | Struts2の「OGNL」ってなに?しくみと使い方をやさしく解説 | 式言語OGNL解説 |
Vol.11.11 | ModelDriven インターフェースの使いどころと注意点 | Model駆動開発 |
Vol.11.12 | SessionAware と RequestAware でセッション/リクエスト管理 | セッション管理 |
Vol.11.13 | Resultタイプ完全解説(dispatcher / redirect / stream など) | 遷移パターン理解 |
Vol.11.14 | Vol.11.14 ValueStackの中身を理解する – 画面とActionの橋渡し役 | Action |
Vol.11.15 | Interceptorチェーンを自作してみよう(ログ / 認証フィルタ) | Interceptor |
Vol.11.16 | エラー処理と例外ハンドリングの実践パターン | ハンドリング設計 |
Vol.11.17 | Struts2でファイルアップロード機能を実装する方法 | 実装系Tips |
Vol.11.18 | 非同期通信(AJAX)とStruts2の連携方法 | フロント連携編 |
Vol.11.19 | セキュリティ対策(CSRF, XSS, パラメータ偽装) | セキュリティ対策 |
Vol.11.20 | 複数フォームを安全に扱う!セッション管理と動的フォームの考え方 | セッション管理 |
Vol.11.21 | Struts2でJSONを返す!REST API連携と非同期通信の基本設計 | セッション管理 |
Vol.11.22 | 本番環境構成とセキュリティ設計(Apache+Tomcat+Struts2連携) | 外部公開 |