✅ 1. ModelDrivenとは何か?
Struts2の ModelDriven
インターフェースは、「フォームの入力値」と「ビジネスロジックで扱うモデルオブジェクト」とを直接結びつけるための仕組みです。
public class CreateUserAction implements Action, ModelDriven<User> {
private User user = new User();
@Override
public User getModel() {
return user;
}
public String execute() {
// user に直接値がバインドされている
return SUCCESS;
}
}
getModel()
で返したオブジェクトに、フォームの値がバインドされます。
通常は setXxx()
があるActionクラスにプロパティをバインドしますが、ModelDrivenを使うとActionクラスをスリムに保てるというメリットがあります。
✅ 2. なぜModelDrivenが使われるのか?
📌 Actionの肥大化を防ぐため
// ModelDrivenを使わない場合
private String name;
private int age;
private String address;
// getter / setter がActionにずらずら…
// ModelDrivenを使うと
private User user; // ← モデルにまとめて管理できる
📌 フォームの構造とドメインモデルの一致
HTMLフォームの構造と、ビジネスロジックで扱う「ユーザ」「商品」などのエンティティが一致しているなら、
そのままModelクラス(POJO)を使った方がシンプルです。
✅ 3. 実際の画面フォームとの連携
<!-- ユーザ作成フォーム -->
<s:form action="createUser">
<s:textfield name="name" label="名前" />
<s:textfield name="age" label="年齢" />
<s:textfield name="address" label="住所" />
<s:submit value="登録" />
</s:form>
上記のようなフォームに対して、ModelDrivenを使うと以下のようにマッピングされます:
public class CreateUserAction implements ModelDriven<User> {
private User user = new User();
public User getModel() {
return user;
}
}
フォームの <s:textfield name="name"/>
は user.name
に自動でバインドされます。
(内部的にOGNLで getModel().setName(...)
が呼ばれます)
⚠️ 4. 注意点と落とし穴
❗ name="name"
ではなく name="user.name"
と書く必要はない?
→ 不要です。
ModelDriven
を使うと、user
は暗黙的に省略されます。
Struts2が getModel()
の戻り値に対して直接バインディングを行うからです。
❗ 複数のフォームを扱う場合
複数のオブジェクトにバインドするような複雑な画面ではModelDriven
は向きません。
1画面1モデル(=単一Model)で使うのが基本。
❗ validate()
や input
に影響はある?
validate()
メソッドで user.getName()
のようにバリデーション対象にアクセスできます。
input result
はそのまま有効。戻った時にも user
モデルに値が保持されています。
✅ 5. ModelDriven + Validationの組み合わせ
以下のように組み合わせることで、Modelクラスにバリデーションロジックを集約できます:
public class CreateUserAction extends ActionSupport implements ModelDriven<User> {
private User user = new User();
public User getModel() {
return user;
}
public void validate() {
if (user.getName() == null || user.getName().isEmpty()) {
addFieldError("name", "名前は必須です");
}
}
}
name
フィールドのエラーとして画面に表示されます。
✅ 6. まとめ
項目 | 説明 |
---|---|
✔ 利点 | Actionがスリムになる。モデルとフォームの構造が一致するなら最適。 |
✔ 使用条件 | 単一のオブジェクトにバインドするシンプルなフォーム。 |
⚠ 注意点 | 複数モデル or フォーム構造が特殊な場合は不向き。 |
✅ Validation |
validate() メソッドで Model を検証できる。 |
📝 おまけ:ModelDrivenとParamバインディングの比較
スタイル | 特徴 | コード例 |
---|---|---|
通常のsetterバインド | フィールド+getter/setterで個別定義 | private String name; |
ModelDriven | モデルクラス1つに集約 |
private User user; + getModel()
|
🚀 次回予告:Vol.11.12 SessionAware と RequestAware でセッション/リクエスト管理
ModelDrivenでデータを綺麗に扱えるようになったら、
次はセッションやリクエストにどのようにデータを保存し管理するかがテーマです。
👉 Struts2の「状態管理」戦略をわかりやすく解説します!
🧭 関連記事(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.4 | 【実践ガイド】ユーザー操作を考慮したアクション遷移設計(リダイレクト vs フォワードの使い分け) | UX遷移設計/Result制御 |
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.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連携) | 外部公開 |