Vol.11.9 バリデーション完全解説（XML / アノテーション）   〜 バリデーションの本質とStruts2実装スタイル別の使い方 〜

Struts2におけるバリデーション処理、あなたはXML派ですか？それともアノテーション派ですか？

本記事では、Struts2が提供するバリデーション機構の全貌を、XML設定とアノテーション設定の両方の観点から完全解説します。Vol.8〜Vol.8.1で触れた`validate()`メソッドや`input`リザルトをベースに、より実践的・体系的な理解へとステップアップしましょう。

---

## ✅ はじめに：バリデーションは"UX設計"そのもの

バリデーション処理は、単なる「入力チェック」ではありません。ユーザーの操作ミスを防ぎ、スムーズな体験を提供するための大切なUX設計要素です。

Struts2は以下の3つのバリデーション手段を用意しています。

| 手段 | 特徴 | 用途 |
|------|------|------|
| 1. `validate()`メソッド | Javaコードで柔軟に記述可能 | 複雑な条件チェックなど |
| 2. XML設定（`-validation.xml`） | Javaコードと分離可能 | 再利用性・保守性重視時 |
| 3. アノテーション | 簡潔で可読性◎ | 単純な検証や小規模PJ向き |

---

## 🧠 1. Struts2のバリデーション処理の全体像

```text
flowchart TD
  入力フォーム --> アクション呼出 --> InterceptorStack --> validation.xml or アノテーション適用 --> エラーならinputへリダイレクト --> エラー表示
```

Struts2では、`defaultStack`に含まれる`validation`インターセプターが、バリデーション処理の中心です。

- バリデーションエラーがあると、自動的に`input`リザルトへ遷移
- エラー情報は`FieldError`に格納され、JSP上で`${fieldErrors}`として出力可能

---

## 🧾 2. XMLによるバリデーション設定

### 📘 基本構文（`YourAction-validation.xml`）

```xml
<validators>
  <field name="username">
    <field-validator type="requiredstring">
      <message>ユーザー名は必須項目です</message>
    </field-validator>
  </field>

  <field name="age">
    <field-validator type="int">
      <param name="min">0</param>
      <param name="max">120</param>
      <message>年齢は0〜120の間で入力してください</message>
    </field-validator>
  </field>
</validators>
```

### 📌 ファイル名と配置場所

- `YourAction-validation.xml` → `YourAction.java` と同じパッケージに配置
- `YourAction-validation-<method>.xml` → 特定のメソッド呼出時に適用

---

## 🧩 3. アノテーションによるバリデーション設定

### 🔍 よく使うバリデーションアノテーション

| アノテーション | 意味 |
|----------------|------|
| `@RequiredStringValidator` | 文字列の必須入力 |
| `@IntRangeFieldValidator` | 整数の範囲制限 |
| `@EmailValidator` | メール形式検証 |
| `@RegexFieldValidator` | 正規表現マッチ |
| `@DateRangeFieldValidator` | 日付の範囲検証 |

### 🧑‍💻 実装例

```java
@Validations(
  requiredStrings = {
    @RequiredStringValidator(fieldName = "username", message = "ユーザー名は必須です")
  },
  intRangeFields = {
    @IntRangeFieldValidator(fieldName = "age", min = "0", max = "120", message = "年齢は0〜120の間で入力してください")
  }
)
public class UserCreateAction extends ActionSupport {
  private String username;
  private int age;

  // getter / setter...
}
```

### ✅ メリット
- コードと検証が一体化しやすい
- 設定が軽量で視認性が高い

---

## 🧠 4. validate()メソッドの活用

より柔軟なバリデーションが必要な場合は、Actionクラスに`validate()`メソッドを定義します。

```java
@Override
public void validate() {
  if (password == null || !password.equals(confirmPassword)) {
    addFieldError("password", "パスワードが一致しません");
  }
}
```

`addFieldError(fieldName, message)` を使って個別のエラーを通知できます。

---

## 🧰 5. 【実務TIPS】XML・アノテーション使い分け戦略

| シーン | 推奨手段 | 理由 |
|--------|----------|------|
| 大規模開発 / チーム開発 | XML | バリデーションの共通化・集中管理がしやすい |
| 小〜中規模 / 個人PJ | アノテーション | 実装が簡単でスピード重視 |
| 特殊なロジック / DBチェック含む | `validate()` | 柔軟な条件式やDB参照処理に強い |

---

## 🔄 バリデーションのエラー表示の例（JSP）

```jsp
<s:fielderror fieldName="username"/>
<s:fielderror fieldName="age"/>
```

全体のエラーメッセージ表示には以下を使います：

```jsp
<s:actionerror />
```

---

## 🧭 まとめ：バリデーション設計は"設計思想"の反映

Struts2のバリデーション機能は「どこまでコードに責任を持たせるか？」という設計思想に直結します。

- アノテーション：**軽量・迅速**
- XML：**保守性・共通化**
- validate()：**柔軟なカスタマイズ**

あなたのプロジェクト規模やチーム体制に応じて、最適なスタイルを選びましょう。

---

## 🧱 次回予告

🔮 **Vol.11.10 「OGNL」ってなに？しくみと使い方をやさしく解説**

バリデーションの裏側で動くOGNL（式言語）に迫ります。Struts2開発で避けて通れないOGNLの基礎をマスターしましょう！

---

## 📚 関連記事リンク（Struts2バリデーション関連）

- [🧩 Vol.11.7 `validate()` / `input` 結合戦略とUX設計 _Struts2におけるユーザー入力バリデーションと、画面遷移制御のベストプラクティス_](https://qiita.com/juehara-crypto/items/ed8f0977c23ee8c8b959)
- [🧩 Vol.11.8 アノテーション vs XML：Struts2開発スタイル徹底比較 _「XML全盛」から「アノテーション時代」へ──Struts2における2つの設定スタイルと実務適用戦略を完全ガイド_](https://qiita.com/juehara-crypto/items/bb2b23612c22fa9bf50b)


---

### 🧭 関連記事（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.Vol.11.4.1](https://qiita.com/juehara-crypto/items/4fd8ed2a8be317f6e1bd)     | 入門者のための自動バインディング実践パターン集                        | 自動バインディング         |
| [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.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連携）                             | 外部公開           |

---