次はSpringBootのinterceptorについて学びましょう

## はじめに
なんだかinterceptorという便利な機能もあるようなので、今日はそれについてまとめてみます。

  - [はじめに](#はじめに)
  - [interceptorとは](#interceptorとは)
  - [こんなことをやってみる](#こんなことをやってみる)
  - [つかってみる。](#つかってみる)
    - [APIの準備](#apiの準備)
    - [interceptorの実装](#interceptorの実装)
    - [登録する](#登録する)
  - [動かしてみる](#動かしてみる)
  - [複数登録する](#複数登録する)
  - [特定の場合のみ登録する](#特定の場合のみ登録する)
  - [え、フィルターと何が違うの？](#えフィルターと何が違うの)
    - [実行されるタイミングが違う](#実行されるタイミングが違う)
    - [どっちを使えばいいの？](#どっちを使えばいいの)
  - [まとめ](#まとめ)

## interceptorとは
割り込み？遮り？

コードと動きを見た方が早そうですね。

## こんなことをやってみる
interceptorを使うとこんなことができるらしいです。

```mermaid
sequenceDiagram
    actor Client
    participant I as Interceptor
    participant B as Business Logic

    Client->>+I: リクエスト
    Note over I: preHandle()<br>前処理<br>(認証、ログ出力など)

    I->>+B: 処理の転送
    B-->>-I: 処理結果

    Note over I: afterCompletion()<br>後処理<br>(ログ出力、リソース解放など)

    I->>-Client: レスポンス
```

## つかってみる。

### APIの準備
いつもの如く、適当なAPIでも用意しましょう。

```java
@RestController
@RequestMapping("/api")
public class SampleApi {

    @GetMapping("/hello")
    public ResponseEntity<String> getHello() {
        System.out.println("Hello, World!");
        return ResponseEntity.ok("Hello, World!");
    }
}

```
### interceptorの実装
次にinterceptorを用意しましょう。前処理と後処理を実装します。

```java
public class LoggingInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) {
        System.out.println("前処理で開始します！");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) {
        System.out.println("後処理で終わります！");
    }
}
```
### 登録する 
interceptorの実行を登録するらしいです。

```java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor());
    }
}
```

## 動かしてみる
こんなのがログに出ました。

```
前処理で開始します！
Hello, World!
後処理で終わります！
```

interceptorを利用して、こんな処理ができました。

```mermaid
sequenceDiagram
    actor Client
    participant I as LoggingInterceptor
    participant A as SampleApi

    Client->>+I: GET /api/hello
    Note over I: preHandle()<br>"前処理で開始します！"

    I->>+A: 処理を転送
    Note over A: "Hello, World!"
    A-->>-I: ResponseEntity.ok("Hello, World!")

    Note over I: afterCompletion()<br>"後処理で終わります！"

    I->>-Client: HTTP Response
```

## 複数登録する
複数のinterceptorを登録することもできます。それぞれ役割の違う処理を入れてみましょう。

```java
// 時間を計測するinterceptor
public class TimingInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) {
        request.setAttribute("startTime", System.currentTimeMillis());
        System.out.println("時間計測開始！");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) {
        long startTime = (Long) request.getAttribute("startTime");
        long endTime = System.currentTimeMillis();
        System.out.println("処理時間: " + (endTime - startTime) + "ms");
    }
}

// 登録を追加
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor());
        registry.addInterceptor(new TimingInterceptor());
    }
}
```

こんなログが出力されます：
```
前処理で開始します！
時間計測開始！
Hello, World!
処理時間: 5ms
後処理で終わります！
```

## 特定の場合のみ登録する
特定のパスにのみ適用することができます。

```java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor())
               .addPathPatterns("/api/**")       // /api/で始まるパスに適用
               .excludePathPatterns("/api/public/**");  // /api/public/は除外

        registry.addInterceptor(new TimingInterceptor())
               .addPathPatterns("/api/hello");   // /api/helloのみに適用
    }
}
```

このように設定することで：
- LoggingInterceptorは `/api/` で始まるパスすべてに適用し、そのなかで`/api/public/`は除外
- TimingInterceptorは `/api/hello` のみに適用

ということで、パブリックに公開するAPIと、ログイン済みユーザーのみ使用できるAPIで分けることができそうですね。

## え、フィルターと何が違うの？

そうなんです。フィルターという似たような機能もあるんですよね。
違いを見ていきましょう。

### 実行されるタイミングが違う
フィルターとinterceptorでは、実行されるタイミングが違うんです。

```mermaid
sequenceDiagram
    actor Client
    participant F as Filter
    participant D as DispatcherServlet
    participant I as Interceptor
    participant C as Controller

    Client->>+F: リクエスト
    Note over F: フィルターは<br>最初に実行される
    F->>+D: 次はここ
    D->>+I: interceptorは<br>ここで実行される
    I->>+C: コントローラーの<br>実行
    C-->>-I: 
    I-->>-D: 
    D-->>-F: 
    F-->>-Client: レスポンス
```


### どっちを使えばいいの？

調べてみると、以下のような使い分けがあるようです。

- filter
  - 全体的な共通処理
- interceptor
  - 機能別の共通処理

よくわかんないけど、、、AIに聞いていたら。。。

```
具体的なユースケース例を見てみましょう：

フィルターの使用例：
- 文字エンコーディングの設定
- CORS（Cross-Origin Resource Sharing）の設定
- セキュリティフィルター（XSS対策など）
- リクエスト/レスポンスのログ記録
- 認証トークンの検証

インターセプターの使用例：
- ユーザーの権限チェック
- APIの実行時間の計測
- トランザクション管理
- 監査ログの記録
- ビジネスロジック実行前後の共通処理

つまり、フィルターは主にWebアプリケーション全体に関わる基盤的な処理を担当し、インターセプターはSpring MVCのコンテキスト内での機能単位の処理を担当すると考えるとよいでしょう。

また、技術的な観点からも以下の違いがあります：

1. 実行タイミング
   - フィルター：ServletContainerレベルで最初に実行
   - インターセプター：Spring MVCのDispatcherServlet後に実行

2. 取得できる情報
   - フィルター：ServletRequest/ServletResponseのみ
   - インターセプター：HandlerMethod（コントローラーのメソッド情報）も取得可能

3. 設定の柔軟性
   - フィルター：URLパターンベースの設定
   - インターセプター：より細かいパスパターン指定が可能

このような特徴を理解した上で、実装する機能に応じて適切な方を選択することが重要です。
```

ですって。頑張って理解しよ。

## まとめ

今回は、interceptorについて整理してみました。何だか filterにも似ていますね。
用途の違いは重要になりそうですね。

フレームワークのパワーをひしひしと感じます。
皆様にとって参考になれば幸いです。

また何か書きます。