Tomcatでフィルタを使う
作成 : 2005/01/01
Tomcatのフィルタ
フィルタを使うと、JSPやサーブレットを処理する事前と事後に、いろいろな処理をすることができるらしい。 決められたIPアドレス以外からのアクセスに対しては、アクセス拒否メッセージのページを表示したり...
フィルタクラス
フィルタを使用するためのクラスを作ってみる。 下の例で、赤い文字が事前・事後の処理を書く部分。 それ以外は、だいたい共通的に使用できるらしい。
/* 標準出力(Tomcatのログ)に文字列を書き出すフィルタ myFilter */ package filters; // (コンテキストパス)/WEB-INF/classes/filtersディレクトリに置くという前提で import javax.servlet.*; import javax.servlet.http.*; public class myFilter implements Filter { private FilterConfig filterConfig; public void init(FilterConfig filterConfig) { this.filterConfig = filterConfig; // フィルタの初期化 } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, javax.servlet.ServletException { System.out.println("myFilter:Before"); // クライアントからのリクエスト時に処理 chain.doFilter(request, response); // 次のフィルタに処理を移す(複数フィルタ適用時) System.out.println("myFilter:After"); // クライアントへのレスポンス時に処理 } public void destroy() { this.filterConfig = null; // フィルタの破棄 } }
あとはコンパイルして、(コンテキストパス)/WEB-INF/classes/filtersディレクトリに置く。
フィルタの定義とマッピング(web.xml)
フィルタを使用するためには、web.xmlでフィルタを定義し、URLまたはサーブレットとのマッピングを指定する。 フィルタを定義するときに、初期化パラメータを指定することができる。
<!-- (コンテキストパス)/WEB-INF/web.xml -->
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<filter> // <filter>〜</filter>でフィルタを定義
<filter-name>myFilter1</filter-name> // フィルタの名前
<filter-class>filters.myFilter</filter-class> // フィルタのクラス名
<init-param> // <init-param>〜</init-param>で初期化パラメータを指定
<param-name>param</param-name> // パラメータの名前
<param-value>1</param-value> // パラメータの値
</init-param>
</filter>
<filter>
<filter-name>myFilter2</filter-name>
<filter-class>filters.myFilter</filter-class>
<init-param>
<param-name>param</param-name>
<param-value>2</param-value>
</init-param>
</filter>
<filter>
<filter-name>myFilter3</filter-name>
<filter-class>filters.myFilter</filter-class>
<init-param>
<param-name>param</param-name>
<param-value>3</param-value>
</init-param>
<init-param> // 初期化パラメータは複数渡すことができる
<param-name>other</param-name>
<param-value>memo</param-value>
</init-param>
</filter>
<filter-mapping> // <filter-mapping>〜</filter-mapping>でマッピングを定義
<filter-name>myFilter1</filter-name> // フィルタの名前
<url-pattern>/*</url-pattern> // URLとのマッピング(先頭にスラッシュがつく)
</filter-mapping>
<filter-mapping>
<filter-name>myFilter2</filter-name>
<servlet-name>Servlet</servlet-name> // サーブレットとのマッピング(先頭にスラッシュがつかない)
</filter-mapping>
<filter-mapping>
<filter-name>myFilter3</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Servlet</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet</servlet-name>
<url-pattern>/HelloWorld</url-pattern>
</servlet-mapping>
</web-app>
フィルタが適用される順番
フィルタが適用される順番は、URLとのマッピング(url-mapping)のほうがサーブレットとのマッピング(servlet-name)より優先される。 あとはfilter-mappingで定義した順番に適用される。
上のweb.xmlと、初期化パラメータparamの値をログに書き出すフィルタmyFilterクラスを使って、フィルタが適用される順番を確認してみる。
/* 初期化パラメータの値をログに書き出す myFilter */
package filters;
import javax.servlet.*;
import javax.servlet.http.*;
public class myFilter implements Filter {
private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
System.out.println("BEFORE:" + filterConfig.getInitParameter("param")); // 赤の部分で初期化パラメータparamの値を取得している
chain.doFilter(request, response);
System.out.println("AFTER:" + filterConfig.getInitParameter("param")); // 赤の部分で初期化パラメータparamの値を取得している
}
public void destroy() {
this.filterConfig = null;
}
}
HelloWorldサーブレットを実行した後、ログ($CATALINA_HOME/logs/catalina.out)を確認してみると、以下のようになっているはず。 filter-mappingで定義された順番は「1 -> 2 -> 3」だが、適用される順番は「1 -> 3 -> 2」となる。 また、この順番はリクエストが渡される順番であり、レスポンスが渡される順番は「2 -> 3 -> 1」となる。
BEFORE:1 <--- myFilter1の出力(url-mapping) BEFORE:3 <--- myFilter3の出力(url-mapping) BEFORE:2 <--- myFilter2の出力(servlet-name) AFTER:2 <--- myFilter2の出力(servlet-name) AFTER:3 <--- myFilter3の出力(url-mapping) AFTER:1 <--- myFilter1の出力(url-mapping)
初期化パラメータを取得する
上の例でもちらっと出てきたが、単一の初期化パラメータを取得するときは、FilterConfigオブジェクトのgetInitParameterメソッドを使う。 複数の初期化パラメータを取得するときは、getInitParameterNamesメソッドを使用する。
/* 初期化パラメータの値をログに書き出す myFilter */
package filters;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
public class myFilter implements Filter {
private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
Enumeration iniParas = filterConfig.getInitParameterNames(); // 赤の部分で初期化パラメータの値を取得している
if(iniParas != null) {
while(iniParas.hasMoreElements()) {
String paraName = (String) iniParas.nextElement();
System.out.println("InitParameterNames(" + paraName + "):" + filterConfig.getInitParameter(paraName));
}
}
chain.doFilter(request, response);
}
public void destroy() {
this.filterConfig = null;
}
}
getInitParameterNamesメソッドの戻り値はEnumerationオブジェクトになるので、java.utilクラスをインポートすること。
ホストベースでアクセス制御する
ServletRequestオブジェクトのgetRemoteAddrメソッドでクライアントのIPアドレスを取得する。 決められたIPアドレス以外からのアクセスの場合は、RequestDispatcherオブジェクトのforwardメソッドで別のページに転送する。
/* 10.1.1.X以外からのアクセスをforward.htmlに転送する myFilter */
package filters;
import javax.servlet.*;
import javax.servlet.http.*;
public class myFilter implements Filter {
private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
String remoteAddress = request.getRemoteAddr(); // getRemoteAddrメソッドでクライアントのIPアドレスを取得
if (remoteAddress.startsWith("10.1.1.")) { // クライアントのIPアドレスが"10.1.1."で始まるならば
chain.doFilter(request, response); // 次のフィルタへ処理を移す
} else {
RequestDispatcher rd = request.getRequestDispatcher("/forward.html"); // 転送するリソースを指定
rd.forward(request, response); // 転送する
}
}
public void destroy() {
this.filterConfig = null;
}
}