🧩 Vol.11.4.1 入門者のための自動バインディング実践パターン集   _Struts2 ParametersInterceptor × OGNLバインディングの“効きどころ”をケース別に完全図解_

## ✅ はじめに

前回の [Vol.11.4](https://qiita.com/juehara-crypto/items/253142d13fe5f604610f) では、Struts2の自動バインディングの仕組みと、`ParametersInterceptor` の役割について解説しました。

本記事では、実際のフォーム入力と Action クラスのプロパティ間でどのようにデータがバインドされるのかを、**具体的なパターンごとに図解的に整理**して解説します。

---

## 🗂️ 目次

1. [単純なプロパティのバインディング](#1-単純なプロパティのバインディング)  
2. [配列とListのバインディング](#3-配列とlistのバインディング)  
3. [Map形式のバインディング](#4-map形式のバインディング)  
4. [チェックボックス・複数選択のケース](#5-チェックボックス複数選択のケース)  
5. [バインディング失敗・型変換エラー時の挙動](#6-バインディング失敗型変換エラー時の挙動) 
6. [オブジェクト型プロパティのネスト](#2-オブジェクト型プロパティのネスト)   
7. [補足：バインディング対象を制御するには？](#7-補足バインディング対象を制御するには)  
8. [まとめと次回予告](#8-まとめと次回予告)

---

## 1. 単純なプロパティのバインディング

もっとも基本的な構成。フォームから送信された入力値が、Actionクラスのプロパティにそのままマッピングされます。

**HTMLフォーム:**
```html
<input type="text" name="userId" />
```

Actionクラス:
```java
private String userId;

public void setUserId(String userId) {
    this.userId = userId;
}
```
---

### 2. 配列とListのバインディング

フォーム名に `[インデックス] `を指定すれば、配列やListにもバインドできます。

**HTMLフォーム:**
```html
<input type="text" name="userIds[0]" />
<input type="text" name="userIds[1]" />
```

**Actionクラス:**
```java
private List<String> userIds = new ArrayList<>();

public void setUserIds(List<String> userIds) {
    this.userIds = userIds;
}
```

📝補足：
JSで動的にフォームを生成する場合、userIds[] のように記述し、送信前にインデックスを付ける手法も一般的です。

>"You can loop them by name or something, and change their name with JavaScript by assigning the right index."
— Stack Overflow


### 3. Map形式のバインディング

フォーム名に `map['key']` 形式を使うことで、Mapにもバインド可能です。

**HTMLフォーム:**
```html
<input type="text" name="params['key1']" />
<input type="text" name="params['key2']" />
```

**Actionクラス:**

```java
private Map<String, String> params = new HashMap<>();

public void setParams(Map<String, String> params) {
    this.params = params;
}
```

---

### 4. チェックボックス・複数選択のケース

チェックボックスや複数選択の`select`は、複数の値が一括でバインドされます。

**HTMLフォーム:**
```html
<input type="checkbox" name="selectedIds" value="1" />
<input type="checkbox" name="selectedIds" value="2" />
```

**Actionクラス:**
```java
private String[] selectedIds;

public void setSelectedIds(String[] selectedIds) {
    this.selectedIds = selectedIds;
}
```

---

### 5. バインディング失敗・型変換エラー時の挙動

例：数値型のフィールドに文字列が送信されると、変換エラーになります。

**HTMLフォーム:**
```html
<input type="text" name="age" value="twenty" />
```

**Actionクラス:**

```java
private int age;

public void setAge(int age) {
    this.age = age;
}
```

この場合 `age` には正しく値がバインドされず、型変換エラーが発生します。Struts2は変換エラーを検知し、適切にエラーメッセージを生成します。



---
## 6. オブジェクト型プロパティのネスト 

**Struts2では、リクエストパラメータのキー名に「.（ドット）」を使うことで、ネスト構造のモデルオブジェクトにも自動で値がセットされます。**

### 🧩 ケース概要

例えば、`User` モデルの中に `name` プロパティを持つ場合、以下のようなリクエストパラメータが送られることで：

```java
user.name=Taro
```

Struts2は **ParametersInterceptor** を通じて以下のような連鎖的バインディング処理を行います：

### 🔁 自動バインディングの流れ

1. `"user.name"` というキーを検出  
2. アクションの `getUser()` を呼び出し、戻り値として `User` オブジェクトを取得  
3. その `User` オブジェクトに対して、`setName("Taro")` を実行  

```text
user.name
    ↓
getUser()
    ↓
Userオブジェクト
    ↓
setName("Taro")
```

このように、**「ネスト構造のオブジェクトにも値をセットできる」** のがStruts2のOGNL×ParametersInterceptorの強みです。

### 💡 実装例
🔹 アクションクラス（Action）
```java
public class RegisterAction extends ActionSupport {

    private User user = new User();

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String execute() {
        // user.getName() や user.getEmail() などを使って処理
        return SUCCESS;
    }
}
```
🔹 モデルクラス（User.java）

```java
public class User {
    private String name;
    private String email;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
```
🔹 HTMLフォーム（JSPなど）
```html
<s:form action="register">
    <s:textfield name="user.name" label="名前"/>
    <s:textfield name="user.email" label="メールアドレス"/>
    <s:submit value="登録"/>
</s:form>

```

🧠 補足：get/set 両方定義する理由
実は、技術的には `getUser()` だけでも内部的に `User` インスタンスが取得できるため、バインディングは可能です。
ただし、以下の理由から `setUser()` も合わせて定義するのが実務では一般的 です。

- DIやユニットテストの都合（モック注入や差し替えが可能に）

- 保守性の向上（将来的に `User` の生成方法を差し替える可能性）

- プロジェクトの設計統一（全フィールドに対して`get/set`ペアを定義）

### ✅ ポイントまとめ

| パターン                           | バインディング方式                 | 備考            |
| ------------------------------ | ------------------------- | ------------- |
| `user.name=Taro`               | `getUser()` → `setName()` | OGNL によるネスト解決 |
| `getUser()` のみ定義               | 動作するが保守性にやや難あり            | 推奨されない設計      |
| `getUser()` + `setUser()` 両方定義 | ◎ベストプラクティス                | 実務ではこの形が主流    |

>🧭 OGNLとParametersInterceptorの連携によって、Struts2はJavaBeans風オブジェクトのプロパティに対しても「パス指定で値を注入する」ことができます。このパターンを理解すれば、複雑なフォームでも柔軟に対応できます！


---

### 7. 補足：バインディング対象を制御するには？

Struts2では以下のような制御が可能です。

- `excludeParams`：特定のパラメータを除外

- `includeParams`：許可するパラメータを明示

- `paramsPrepareParamsStack`：Prepare処理 → パラメータ設定 の順に制御できるStack

>"This interceptor gets all parameters from ActionContext and sets them on the ValueStack via OGNL."
— Apache Struts: Parameters Interceptor

---

### 8. まとめと次回予告
本記事では、Struts2における **自動バインディングの実際の動作** を、以下のようなパターン別に解説しました：

- 単純なプロパティ

- オブジェクトネスト

- 配列・リスト

- Map形式

- チェックボックス・セレクト

- 型変換エラーの挙動

---

👉 次回予告
**Vol.11.5：struts.xml完全理解ガイド（仮）**
設定ファイルの構成・設計・ベストプラクティスを深掘りしていきます。


---

### 🧭 関連記事（Vol.11.xxxシリーズ）
| 連番           | タイトル                                                  | 内容分類              |
| ------------ | ----------------------------------------------------- | ----------------- |
| [Vol.11.0](https://qiita.com/juehara-crypto/items/a0cc66893cb499a6e23a)     | Struts2が提供してくれる便利機能まとめ9選                              | 導入＆概要             |
| [Vol.11.1](https://qiita.com/juehara-crypto/items/0a584da537059dd43a7c)     | 自動注入とステートレスActionの仕組み                                 | フレームワーク内部理解       |
| [Vol.11.2](https://qiita.com/juehara-crypto/items/c69962826bb29639c351) | **UX改善に効く！アクション層設計と入力制御の極意（プロローグ）**                   | UX設計・アクション層総論     |
| [Vol.11.2.1](https://qiita.com/juehara-crypto/items/9ca115073e6f928c7f71)   | 【実践編】Struts2アクション層の役割と設計パターン（Command型 / UIアクション分離など）  | アクション設計パターン       |
| [Vol.11.2.2](https://qiita.com/juehara-crypto/items/88b7634a64b1ad564668)   | 【UX重視】戻るボタン・キャンセル処理の設計手法と「戻り先管理」のスマート実装               | 戻り先制御とUX設計        |
| [Vol.11.2.3](https://qiita.com/juehara-crypto/items/c5165c92a4366fd1962b)   | 【設計ノウハウ】多画面遷移時のパラメータ受け渡し・保持戦略（セッション vs hidden vs URL） | パラメータ多重管理         |
| [Vol.11.2.4](https://qiita.com/juehara-crypto/items/06162659215cca86de28)   | 【実践ガイド】ユーザー操作を考慮したアクション遷移設計（リダイレクト vs フォワードの使い分け）     | UX遷移設計／Result制御   |
| [Vol.11.2.5](https://qiita.com/juehara-crypto/items/b538b50eaa9c263a31bb)   | 【トラブル防止】アクション層の共通処理とメンテナブルなBaseAction設計               | アクション共通化／保守性      |
| [Vol.11.3](https://qiita.com/juehara-crypto/items/913de7c942a9242201e8)     | Struts2の defaultStack とは？Interceptorの中身を詳しく追ってみる      | Interceptor       |
| [Vol.11.3.2](https://qiita.com/juehara-crypto/items/ede8d3c2a9b147f6161e)     | 🔧 Vol.11.3.2 独自Interceptorの作り方と使い所 _Struts2のカスタマイズを“実践で使えるレベル”に一歩進めよう_     | Interceptor       |
| [Vol.11.4](https://qiita.com/juehara-crypto/items/253142d13fe5f604610f)     | 入門者のための「パラメータ自動バインディング」完全理解ガイド                        | 自動バインディング         |
| [Vol.11.5](https://qiita.com/juehara-crypto/items/6ef7a87a54163d81a9ba)     | Struts2の構成理解が“実務レベル”へと進化する決定版         | 設定ファイル構造          |
| [Vol.11.5.1](https://qiita.com/juehara-crypto/items/df407b24101e92a02eab)     | Struts2の“画面遷移の全体像”を理解するためのマイルストーン記事         | 設定ファイル構造          |
| [Vol.11.6](https://qiita.com/juehara-crypto/items/bfbdc2203acac7ba3f19)     | ActionSupport の便利メソッドと国際化対応                           | ユーティリティ / i18n    |
| [Vol.11.7](https://qiita.com/juehara-crypto/items/ed8f0977c23ee8c8b959)     | validate() / input 戦略とUX設計                            | 開発スタイルの違い    
| [Vol.11.8](https://qiita.com/juehara-crypto/items/bb2b23612c22fa9bf50b)     | アノテーションベースの設定 vs XML定義の比較                             | 開発スタイルの違い         |
| [Vol.11.9](https://qiita.com/juehara-crypto/items/6163ad6c9308cc8dda6d)     | バリデーション完全解説（XML / アノテーション）                            | バリデーション（※Vol.8補完） |
| [Vol.11.10](https://qiita.com/juehara-crypto/items/207cb3d7f0a889c54df9)     | Struts2の「OGNL」ってなに？しくみと使い方をやさしく解説                     | 式言語OGNL解説         |
| [Vol.11.11](https://qiita.com/juehara-crypto/items/c313ea56f97984756c05)    | ModelDriven インターフェースの使いどころと注意点                        | Model駆動開発         |
| [Vol.11.12](https://qiita.com/juehara-crypto/items/de7a17d53e53d6466f17)    | SessionAware と RequestAware でセッション/リクエスト管理            | セッション管理           |
| [Vol.11.13](https://qiita.com/juehara-crypto/items/539bd5bae75a8e154753)    | Resultタイプ完全解説（dispatcher / redirect / stream など）      | 遷移パターン理解          |
| [Vol.11.14](https://qiita.com/juehara-crypto/items/142d9aa2c623c5eb70bc)    | Vol.11.14 ValueStackの中身を理解する – 画面とActionの橋渡し役                 | Action            |
| [Vol.11.15](https://qiita.com/juehara-crypto/items/84f024816d0cf2212cb6)    | Interceptorチェーンを自作してみよう（ログ / 認証フィルタ）                 | Interceptor            |
| [Vol.11.16](https://qiita.com/juehara-crypto/items/ff3ad75f9ee45fcd0f8f)    | エラー処理と例外ハンドリングの実践パターン                                 | ハンドリング設計          |
| [Vol.11.17](https://qiita.com/juehara-crypto/items/0d8d5101ff39b34b4704)    | Struts2でファイルアップロード機能を実装する方法                           | 実装系Tips           |
| [Vol.11.18](https://qiita.com/juehara-crypto/items/d93c8d9cee719997c068)    | 非同期通信（AJAX）とStruts2の連携方法                              | フロント連携編           |
| [Vol.11.19](https://qiita.com/juehara-crypto/items/dd6cf06d3100c9204d1f)    | セキュリティ対策（CSRF, XSS, パラメータ偽装）                              | セキュリティ対策           |
| [Vol.11.20](https://qiita.com/juehara-crypto/items/9442d9f4705f1c6c4da1)    | 複数フォームを安全に扱う！セッション管理と動的フォームの考え方                              | セッション管理           |
| [Vol.11.21](https://qiita.com/juehara-crypto/items/78eb217727b7c97f228a)    | Struts2でJSONを返す！REST API連携と非同期通信の基本設計                              | セッション管理           |
| [Vol.11.22](https://qiita.com/juehara-crypto/items/424155ee0e567a36b9a1)    | 本番環境構成とセキュリティ設計（Apache+Tomcat+Struts2連携）                             | 外部公開           |

---