Javaのメモ(struts)

## はじめに
StrutsとSpringの連携とかがあるようです。

## struts-config.xml
```struts-config.xml
<action path="/AB001S"
 type ="org.springframework.web.struts.Delegating Action Orixy"
 name= "AB001SForm"
 parameter="display,create,register,back"
 validate="false"
 scope="request">
<forward name="display" path="/ikusaki/AB001S.jsp">
<forward name="AZ0020A" path="/AZ0020S.do?display="back">
</action>
```
 `struts-config.xml` ファイルの記載に関する説明をします。

まず、`struts-config.xml` は、Struts フレームワークの設定ファイルで、リクエストに対するアクションやビューへのフォワードを管理しています。この記述では、Spring と Struts が連携している部分も見られます。詳細に説明します。

### `<action>` タグの説明

```xml
<action path="/AB001S"
       type="org.springframework.web.struts.Delegating Action Proxy"
       name="AB001SForm"
       parameter="display,create,register,back"
       validate="false"
       scope="request">
```

1. **`path="/AB001S"`**:
   - このアクションが処理するリクエストパスを指定します。`/AB001S` に対するリクエストがこのアクションにルーティングされます。

2. **`type="org.springframework.web.struts.Delegating Action Proxy"`**:
   - ここでは、Struts が Spring の `DelegatingActionProxy` クラスを使って Spring にアクションの処理を委譲しています。このクラスは、Struts のアクション処理を Spring のビジネスロジックに結び付けます。Spring と Struts を連携させる設定です。

3. **`name="AB001SForm"`**:
   - このアクションが操作するフォーム Bean の名前を指定しています。`AB001SForm` という名前のフォームオブジェクトが使用されることを示しています。

4. **`parameter="display,create,register,back"`**:
   - このパラメータは、異なる操作に対応するアクションメソッドやパスを指定しています。例えば、`display` や `create`、`register`、`back` といったアクションがリクエストに応じて異なる処理を実行することができます。

5. **`validate="false"`**:
   - このアクションに対して、フォームのバリデーションを行わない設定です。`false` に設定されているので、フォーム送信時にデフォルトのバリデーションは実行されません。

6. **`scope="request"`**:
   - このアクションに関連付けられているフォーム Bean のスコープを指定しています。`request` スコープは、リクエスト単位でフォームオブジェクトが生成され、次のリクエストではリセットされることを意味します。

### `<forward>` タグの説明

アクションが完了した後、どのビューや次のアクションにフォワードするかを指定しています。

```xml
<forward name="display" path="/ikusaki/AB001S.jsp">
```
- **`name="display"`**:
  - この名前でアクションの結果が「display」の場合にフォワードされます。

- **`path="/ikusaki/AB001S.jsp"`**:
  - 具体的な JSP ページへのパスです。この場合は、`/ikusaki/AB001S.jsp` という JSP ページにリクエストがフォワードされ、そこで HTML を生成します。

```xml
<forward name="AZ0020A" path="/AZ0020S.do?display=back">
```
- **`name="AZ0020A"`**:
  - アクション結果が「AZ0020A」の場合にフォワードされる。

- **`path="/AZ0020S.do?display=back"`**:
  - この場合、`/AZ0020S.do` という別のアクションにフォワードされます。この際、クエリパラメータとして `display=back` が付与されています。次のアクションがこのパラメータを基に処理を行います。

### まとめ

- このアクションでは、Spring と Struts の連携を実現するために `DelegatingActionProxy` を使っているため、リクエスト処理は Spring のコンテキストで行われます。
- 複数のパラメータを持つアクションで、結果に応じて JSP ページや別のアクションにフォワードしています。
- この設定は、複数の操作に対応するアクションを一つのエントリポイントに集約するためのものです。


## ○○Action.java の findForward() メソッドで返された値
`<forward name="display" path="/ikusaki/AB001S.jsp">` で指定された `name="display"` という値は、`○○Action.java` の `findForward()` メソッドで返された値に対応しています。

具体的には、Strutsの `Action` クラスの `execute()` メソッド内でビジネスロジックが処理され、その結果に応じて `mapping.findForward("display")` が呼ばれます。このとき、`findForward("display")` は、`struts-config.xml` に定義されている `forward` の `name` 属性と一致するビューやアクションにフォワードします。

### 例: `○○Action.java` 内での `findForward()` の使用

例えば、以下のように `○○Action.java` で `findForward()` を使用しているとします。

```java
public class AB001SAction extends Action {
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response) throws Exception {
        
        // 何らかのビジネスロジックを実行
        // 例えば、リクエストから取得した値をもとに処理

        // "display" に基づいてビューを返す
        return mapping.findForward("display");
    }
}
```

### `struts-config.xml` 内での `forward` 設定

```xml
<action path="/AB001S"
       type="com.example.AB001SAction"
       name="AB001SForm"
       scope="request"
       validate="false">
    <forward name="display" path="/ikusaki/AB001S.jsp" />
</action>
```

この場合、`AB001SAction.java` の `execute()` メソッド内で `mapping.findForward("display")` を呼び出すと、`struts-config.xml` 内の `<forward name="display" path="/ikusaki/AB001S.jsp">` に定義されている `path="/ikusaki/AB001S.jsp"` へリクエストがフォワードされます。

### まとめ

- **`findForward("display")` の値** は、`struts-config.xml` の `<forward name="display">` で定義された `name="display"` と一致します。
- `findForward("display")` が返す `ActionForward` オブジェクトは、`struts-config.xml` に記載された `path="/ikusaki/AB001S.jsp"` にリクエストをフォワードし、そのJSPを表示します。

したがって、`○○Action.java` 内で `findForward("display")` を呼び出した結果が、`struts-config.xml` 内の `name="display"` と一致し、その結果として `/ikusaki/AB001S.jsp` が表示されることになります。

## StrutsとSpringが連携
StrutsとSpringが連携して動作している場合、まずStrutsのアクションが起動されるか、Springのコンテキストで処理が開始されるかの理解について説明します。

この場合、`struts-config.xml` で指定されている `DelegatingActionProxy` は、StrutsからSpringへアクション処理を委譲するための機能です。具体的な流れを整理すると以下のようになります。

### StrutsとSpringの連携の流れ

1. **Strutsがリクエストを受け取る**:
   - まず、Strutsが `struts-config.xml` に基づいてリクエストをルーティングします。この際、指定されたURLパターン（例えば `/AB001S`）に一致するアクションを探します。

2. **`DelegatingActionProxy`の呼び出し**:
   - `struts-config.xml`で指定されている `type="org.springframework.web.struts.DelegatingActionProxy"` は、リクエストが来た時に Struts のアクションではなく、Spring のコンテキストに委譲するプロキシクラスです。
   - これにより、Strutsはリクエスト処理を `DelegatingActionProxy` に委譲します。このプロキシはSpringの設定ファイル（通常は `applicationContext.xml`）内に定義されているSpringのビーン（Springのアクションクラス）を探して処理します。

3. **Springのアクションが呼び出される**:
   - Springのコンテキストがロードされ、StrutsのアクションはSpringのビーンとして定義されたアクション（例えば `AB001SAction.java`）に処理を委譲します。
   - このSpringビーンがビジネスロジックを実行します。

4. **結果を返してJSPにフォワードする**:
   - Springのアクションが処理を終えると、`struts-config.xml` に定義されている `forward` 設定に基づいて、JSPや次のアクションにフォワードします。JSPは通常通り、サーバサイドのJSPコンテナでレンダリングされます。

基本的に以下の考え方が正しいです：

- **Strutsがリクエストを受け、Springのコンテキストに委譲**：
  最初にStrutsがリクエストを受け取り、そのリクエストを `DelegatingActionProxy` を介してSpringに委譲します。ですので、`AB001SAction.java`のようなアクションが起動される時、実際にはSpringのコンテキスト内でそのアクションが管理されています。

- **JSPの処理とSpringの関係**：
  Strutsがフォワード先のJSPページにリクエストを渡す部分は、Strutsの機能で行われます。JSPの処理自体は通常のJSPコンテナで行われ、直接Springのコンテキストを利用することはありません。ただし、JSPページでSpringのタグライブラリを利用することによって、Springのコンポーネントにアクセスすることが可能です。

まとめると、**リクエストの流れは最初にStrutsが受け取り、アクション処理はSpringに委譲され、その後JSPにフォワードされる** という形になります。

## StrutsとSpringが連携時の境目
StrutsとSpringを組み合わせて使う場合、特に`DelegatingActionProxy`などを介してリクエスト処理がSpringに委譲されるケースでは、両者の役割分担がわかりにくくなることがあります。確かに、フレームワーク間の境界が曖昧になると、運用面でのトラブルが心配になることは理解できます。ここでは、**StrutsとSpringの役割を明確にし、運用の自由度を管理する方法**について解説します。

### StrutsとSpringの役割分担

1. **Strutsの主な役割**:
   - リクエストのルーティング：StrutsはリクエストURLに基づいて適切なアクションを選択します。
   - フォワーディング：処理結果に応じてJSPや他のアクションにフォワードする役割を担います。
   - `Action` クラスは、リクエストのハンドリングのエントリポイントとして機能し、`struts-config.xml` に基づいて動作します。

2. **Springの主な役割**:
   - ビジネスロジックの処理：SpringはDI（依存性注入）とAOP（アスペクト指向プログラミング）を利用し、ビジネスロジックを効率的に管理します。
   - サービス層とデータアクセス層：Springのサービス層やリポジトリ層は、ビジネスロジックやデータベースとのやり取りを担当します。
   - Strutsがアクションを処理する際に、実際のビジネスロジックをSpringに委譲することで、Separation of Concerns（関心の分離）を達成します。

### 典型的な分け方

- **Strutsの役割**: 基本的にユーザーからのリクエストを受け取り、そのリクエストをSpringに渡すための窓口として機能します。リクエストのルーティングや、処理結果に基づくJSPや次のアクションへのフォワードを担当します。
- **Springの役割**: 具体的なビジネスロジックや、データベースとのやり取りなど、リクエストを処理する本質的な部分を担当します。`ServiceImpl` や `Repository` クラスを用いて、ビジネスロジックを実行します。

### 境界を明確にする方法

1. **役割を明確に定義する**:
   - Strutsは基本的に「リクエストの受け取りとレスポンスの返却（フォワーディング）」を行い、ビジネスロジックやデータ処理はSpringのサービス層に完全に委譲する形にします。
   - 例えば、Strutsの `Action` クラス内でビジネスロジックを実装するのではなく、Springの `Service` に委譲するような明確な方針を持つことが重要です。

2. **統一された設定とドキュメントの整備**:
   - `struts-config.xml` や Spring の設定ファイル（`applicationContext.xml` など）で役割を明確に分け、それぞれの責任範囲をドキュメント化します。設定ファイルに適切なコメントを入れることも有効です。
   - 開発チーム全体で、どこまでがStrutsの責任でどこからがSpringの責任かを共通理解にしておくと、メンテナンス性が向上します。

3. **アクションとサービスの依存関係を最小限にする**:
   - Strutsの `Action` クラスはできるだけ薄く保ち、具体的なビジネスロジックはすべてSpringの `Service` クラスに任せるようにします。これにより、どの部分がStrutsで、どの部分がSpringかが明確になります。

4. **適切なエラーハンドリングとトランザクション管理**:
   - StrutsとSpringが混在するシステムでは、エラーハンドリングやトランザクション管理が複雑になる可能性があります。SpringのAOPやトランザクション管理を活用し、ビジネスロジックを処理する際のエラーハンドリングやトランザクション管理を統一することで、運用の自由度が保たれます。

### 運用面でのアドバイス

- **テストを徹底する**: StrutsとSpringが連携するシステムでは、両者の境界が曖昧になる可能性があるため、ユニットテストや統合テストをしっかりと実施することが重要です。StrutsのアクションとSpringのサービスが適切に連携しているかを確認します。
  
- **ログ管理の強化**: 両フレームワーク間の処理がどこで行われているかを明確に把握できるように、適切なログ出力を行うことも運用面で重要です。特にエラーが発生した場合にどのレイヤーで起こったかを特定しやすくするためです。

- **トレーニングとガイドライン**: 開発者全員がStrutsとSpringの両方の役割と機能を理解していることが大切です。ガイドラインやコーディング規約を定め、適切な運用ができるようにしておくと良いでしょう。

### 結論

StrutsとSpringを併用する際の運用は、役割分担とその境界がわかりにくくなることがありますが、各フレームワークの責任範囲を明確にし、Strutsはリクエスト管理とフォワーディング、Springはビジネスロジックを担当するという方針で進めると管理しやすくなります。また、適切なドキュメンテーションとガイドラインを作成し、運用を統制することが成功の鍵となります。

## 現状
現状では **Strutsはあまり使われていない** 傾向にあり、代わりに **Spring（特にSpring MVCやSpring Boot）** が主流になっています。現在の主流は、XMLベースの設定をほとんど使わずに、**アノテーション** を使ってルーティングや他の設定を行う形に移行しています。

### Springの現状について

- **Springアノテーションによるルーティング**:
  Springでは、以前は `applicationContext.xml` などのXMLファイルを使用してルーティングや依存性注入の設定を行っていましたが、現在ではアノテーションを用いた設定が一般的です。Spring MVCやSpring Bootでは、コントローラクラスで直接アノテーションを使ってルーティングを定義します。

  例えば、次のように `@RequestMapping` などのアノテーションを使ってルーティングを簡単に設定できます。

  ```java
  @RestController
  @RequestMapping("/example")
  public class ExampleController {

      @GetMapping("/hello")
      public String sayHello() {
          return "Hello, World!";
      }

      @PostMapping("/submit")
      public String handleSubmit(@RequestBody FormData formData) {
          // ビジネスロジック
          return "Data submitted";
      }
  }
  ```

  このように、`@RequestMapping` や `@GetMapping`、`@PostMapping` を使うことで、URLに対するルーティングを簡単に定義できます。**XMLを使わずに完全にアノテーションベースでルーティングや設定を行うことができます**。

### Spring Bootの登場でさらに簡略化

- **Spring Boot** は、Springアプリケーションをより簡潔に、設定を最小限にして開発できるようにしたフレームワークです。Spring Bootでは、必要な設定や依存性が自動的に解決され、**XMLファイルや複雑な設定ファイルをほとんど使わずに開発できる**のが特徴です。
  
  - 例えば、Spring Bootでは、`application.properties` や `application.yml` ファイルで最小限の設定を行うだけで、依存性の設定やルーティング、ビジネスロジックの構築が可能です。

### Spring一択の理由

- **モダンな開発**: Springは、最新のアプリケーション開発の要件に合致しており、マイクロサービスやクラウドネイティブアーキテクチャに対応しています。Spring Bootを使えば、REST API、データベース接続、セキュリティなどの機能がすぐに利用できる状態で提供されます。
  
- **アノテーションによる簡潔さ**: アノテーションベースの設定により、コード内でロジックと設定をシンプルに管理できます。たとえば、コントローラークラスに `@RestController` を付けるだけで、そのクラスがREST APIとして動作するようになります。

- **テストの容易さ**: Springはテストも強力にサポートしており、アノテーションによって設定が簡単になっているため、ユニットテストや統合テストの環境を簡単にセットアップできます。

### まとめ

現在のトレンドは **Spring一択** と言ってもよいほどにSpringが主流です。Strutsのようなフレームワークはほとんど使われなくなり、Springでは **アノテーション** を使ってルーティングや依存性の注入などを管理する形が一般的です。また、Spring Bootの登場により、XMLを使わずに、より簡潔に設定が可能になっています。

そのため、現代のJavaアプリケーション開発では、XMLを使わず、アノテーションでルーティングを行うのが標準的なやり方と考えて良いでしょう。

## StrutsのServiceクラスについて
Strutsには、Springのような「**Serviceクラス**」という公式な概念はありません。Strutsは、主にMVC（Model-View-Controller）アーキテクチャの「コントローラ」部分に焦点を当てたフレームワークです。つまり、**リクエストを受け取って、適切なビューにフォワードすること**が主な役割です。ビジネスロジックを含む部分は、Struts自体が強制的にどこに置くかを定めているわけではありません。

そのため、Strutsには以下のような特徴があります。

### Strutsの役割
- **Actionクラス**: リクエストを処理するためのコントローラー役割を果たすクラスです。リクエストパラメータを処理し、ビュー（JSPなど）にフォワードします。
- **Formクラス**: リクエストで送信されたデータを受け取るためのクラスで、フォームのデータを保持し、必要に応じてバリデーションを行います。
- **struts-config.xml**: リクエストとアクション、ビューのルーティングを設定するためのXMLファイルです。

ただし、Strutsにはビジネスロジックを処理する明確な場所は定義されていません。つまり、Struts自体は**ビジネスロジックの設計には関与しておらず、他のレイヤー（例えばサービス層）を独自に実装する必要がある**のです。

### Springとの違い
Springの場合、ビジネスロジックを処理する層として**サービスクラス（`@Service`）**があり、ビジネスロジックとコントローラ層を分離するための明確な役割分担が設けられています。

一方、Strutsでは、そのような設計は強制されていません。そのため、Strutsアプリケーションの開発者は、ビジネスロジックの管理方法を独自に決める必要があります。

- **ビジネスロジックの配置**: Strutsでは、ビジネスロジックを `Action` クラスに直接書くこともできますが、これではコードが肥大化し、再利用性やテストのしやすさが損なわれます。よって、多くのプロジェクトでは、サービスクラスのような層を独自に作成し、ビジネスロジックをそちらに委譲します。
  - 例えば、`UserService` というクラスを独自に作成し、その中にユーザーに関するビジネスロジックを実装し、Strutsの `Action` クラスでは `UserService` を呼び出すような形に設計されることが一般的です。

### Strutsでのサービス層の設計例

たとえば、StrutsアプリケーションでSpringのようなサービス層を自作する場合、次のように実装します。

1. **サービスクラスの作成**:
   - ビジネスロジックを処理する `UserService` クラスを作成します。

   ```java
   public class UserService {
       public void registerUser(User user) {
           // ユーザー登録のビジネスロジック
       }
   }
   ```

2. **Actionクラスでサービスを呼び出す**:
   - `Action` クラス内で、サービスを利用します。

   ```java
   public class UserAction extends Action {
       private UserService userService = new UserService();

       public ActionForward execute(ActionMapping mapping, ActionForm form,
                                    HttpServletRequest request, HttpServletResponse response) {
           UserForm userForm = (UserForm) form;
           User user = new User(userForm.getName(), userForm.getEmail());

           // サービスクラスを利用してビジネスロジックを処理
           userService.registerUser(user);

           return mapping.findForward("success");
       }
   }
   ```

このように、Strutsアプリケーションにおいては、**サービスクラスやその他のビジネスロジックを分離した層は開発者が独自に設計すること**が一般的です。公式に定められた「Serviceクラス」のような構成はありませんが、設計の一環として取り入れることが推奨されています。

### まとめ

- **Strutsには公式な「Serviceクラス」の概念はない**ため、ビジネスロジックをどのように分離するかは開発者に委ねられています。
- ただし、**サービス層を独自に実装する**ことで、StrutsアプリケーションでもSpringと同様にビジネスロジックを明確に分離し、テストや保守性を向上させることができます。
- 現代のフレームワークであるSpringでは、この役割が標準的に定義されているため、設計がよりスムーズに進められることが特徴です。