2007 年 4 月 12 日 23 時 56 分

Filter: Servlet の汎用的なフック機構


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


Filter を使うと、Servlet の処理に介入し、
その実行の前後で特別な処理を挟むことができる。

Filter の強みは、汎用的なところである。

あらゆる Servlet に適用することが可能だけでなく、
普通の HTML や CSS などの静的なコンテンツに対しても、
自由に前処理や後処理をすることができる。

まあ、「静的」なコンテンツと言ったところで
Servlet コンテナの既定処理(default servlet)で
処理されているから、結局は Servlet として扱えるのだ。

では、要求文字エンコーディングを UTF-8 にするための
独自のフィルタを作ってみよう。

========== UTF8RequestFilter.java ==========
package jp.loafer.test.filters;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class UTF8RequestFilter implements Filter {

    public UTF8RequestFilter() {
    }

    public void init(FilterConfig config)
            throws ServletException {
        // フィルタ自身の初期化は不要
    }

    public void destroy() {
        // フィルタ自身の後始末は不要
    }

    public void doFilter(ServletRequest request,
            ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        // 入力エンコーディングが不明なら UTF-8 にする
        String encoding = request.getCharacterEncoding();
        if (encoding == null || encoding.length() == 0) {
            request.setCharacterEncoding("UTF-8");
        }

        // 次の Filter または Servlet を呼び出し、
        // 本来の処理に戻って続行する
        chain.doFilter(request, response);

        // 必要なら、ここで後処理も行える

    }

}
========== end of SetUTF8Request.java ==========

ざっとこんな感じ。

Filter インタフェースは非常にシンプルだ。
init と destroy は、Filter の準備と後始末のためである。
SetUTF8Request は単純なフィルタなので、
初期化や後始末は必要ない。

フックを行うのが、doFilter メソッドである。
request と response はお馴染みのコンビだ。
これらを好き勝手に操作することで、
Servlet が実行される前に処理を行うことができる。

今回の実装では、request を調べ、
文字エンコーディングが設定されていない場合のみ、
「UTF-8」を設定しておくことにした。
万が一設定されていた場合はそれに従う方が良いからだ。

doFilter にはもうひとつ、chain 引数があるが、
これまた単純で、doFilter メソッド 1 つしかない、
単純なインタフェースである。

この FilterChain#doFilter を呼びだすことで、
本来の処理に制御を移すことができる。
もし、呼び出さなければ何も実行されることはない。

Filter は何段も重ねることができ、
各フィルタはチェーン状につながっている。
そのため、FilterChain#doFilter で呼び出されるのは、
Servlet に限らず、別のフィルタに制御が移ることもある。

また、メソッドを呼び出した後に処理を行えば、
Servlet の処理を確認後、追加処理を行うことも可能となる。

FilterChain#doFilter の引数は例のコンビだが、
これらのラッパクラスを作り
request と response の代わりに渡すなどすれば、
圧縮や暗号化、データ形式変換等も自由に行うことができる。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.