❗ Vol.11.16 エラー処理と例外ハンドリングの実践パターン（Struts2）



> Struts2での「エラー処理」「例外ハンドリング」の基本から、実務に役立つパターンまでを解説。堅牢なWebアプリを支える必須設計です。

---

## ✅ 1. なぜ例外ハンドリングが重要か？

エラーは必ず発生します。Struts2でも以下のような場面で例外が起こります。

- DAOでのSQL例外
- サービス層でのNullPointerException
- ユーザ入力ミス
- 権限のないアクセス

**ポイント：例外は握りつぶさず、「ハンドリング」する。**

---

## ✅ 2. Struts2の例外処理 3つの基本パターン

### 💡 パターン①：try-catchによる個別ハンドリング

```java
public String execute() {
    try {
        userService.save(user);
        return SUCCESS;
    } catch (SQLException e) {
        addActionError("DBエラーが発生しました");
        return ERROR;
    }
}
```

### ✅ メリット：
- エラー内容に応じて適切にUIへ反映できる

- 細かな制御が可能

### ❌ デメリット：
- 重複が多くなりがち

- コードが散らかる

---

### 💡 パターン②：共通例外ハンドラを `struts.xml` で定義

```xml
<global-exception-mappings>
  <exception-mapping exception="java.sql.SQLException" result="dberror"/>
  <exception-mapping exception="java.lang.Exception" result="error"/>
</global-exception-mappings>

<action name="saveUser" class="com.example.SaveUserAction">
  <result name="success">/success.jsp</result>
  <result name="dberror">/dbError.jsp</result>
  <result name="error">/generalError.jsp</result>
</action>

```

### ✅ メリット：
- 全体で一貫性のある例外処理

- コード量を減らせる

### ❌ デメリット：
- 詳細な対応が難しい

- エラー内容の表示には工夫が必要

---

### 💡 パターン③：Interceptorによる横断的エラーハンドリング

```java
public class ExceptionInterceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        try {
            return invocation.invoke();
        } catch (SQLException e) {
            ActionContext.getContext().put("errorMessage", "DBエラーが発生しました。");
            return "dberror";
        } catch (Exception e) {
            ActionContext.getContext().put("errorMessage", "不明なエラーが発生しました。");
            return "error";
        }
    }
}

```

✅ メリット：
- ロジックとエラーハンドリングを分離できる

- 全アクションに適用可能で便利


### ✅ 3. 実務でよくある「例外種別」と対応例

| 例外種別                      | 対応                                |
| ------------------------- | --------------------------------- |
| `SQLException`            | DBエラー画面に遷移（復旧方法やサポート連絡先を表示）       |
| `NullPointerException`    | 原因不明のシステムエラーとして報告画面へ遷移            |
| `BusinessException`（独自例外） | ユーザーに分かる形で表示 (`addActionError`使用) |
| `AuthenticationException` | ログイン画面や権限エラーページへ                  |


---

### ✅ 4. UIへのフィードバック：`addActionError`, `addFieldError`
`addActionError("エラーです")`：画面上部にエラーメッセージ表示

`addFieldError("email", "メールアドレスが不正です")：`該当フォームフィールドの下にエラー表示

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

---

### ✅ 5. ログとの連携（Log4j / SLF4J）
```java
private static final Logger logger = LoggerFactory.getLogger(MyAction.class);

try {
    ...
} catch (Exception e) {
    logger.error("処理中に例外発生", e);
}
```

- **例外発生時のスタックトレースは必ずログに出す**

- ユーザー画面ではスタックトレースを絶対に見せない

---

### ✅ 6. エラー画面の設計指針
- 「何が起きたか」だけでなく「どうすれば良いか」も表示

- 例：
```text
システムエラーが発生しました。
数分後に再試行するか、管理者にご連絡ください。
```

- ログイン状態やセッション切れによっては自動でログイン画面へ遷移させる



### ✅ 7. まとめ：ハンドリング設計の基本方針


| 項目       | 指針                                     |
| -------- | -------------------------------------- |
| 発生原因の記録  | ログ出力を忘れずに（Log4j / SLF4J）               |
| ユーザーへの表示 | addActionError / 専用画面で丁寧に伝える           |
| コード構造    | try-catch／Interceptor／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.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.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.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連携）                             | 外部公開           |

---