Filterインターフェース

広告

ではフィルタとして呼び出されるサーブレットの作成方法について見ていきます。フィルタを作成するにはFilterインターフェースを実装したクラスを作成します。

フィルタインターフェースを実装するには次の3つのメソッドを実装する必要があります。

Called by the web container to indicate to a filter that it is being 
placed into service. The servlet container calls the init method exactly 
once after instantiating the filter. The init method must complete 
successfully before the filter is asked to do any filtering work. 

The web container cannot place the filter into service if the init 
method either
1.Throws a ServletException 
2.Does not return within a time period defined by the web container 

Throws: 
  ServletException

"init"メソッドはフィルタの初期化処理に使います。

Called by the web container to indicate to a filter that it is being taken 
out of service. This method is only called once all threads within the 
filter's doFilter method have exited or after a timeout period has passed. 
After the web container calls this method, it will not call the doFilter 
method again on this instance of the filter. 

This method gives the filter an opportunity to clean up any resources that 
are being held (for example, memory, file handles, threads) and make sure 
that any persistent state is synchronized with the filter's current state 
in memory.

"destroy"メソッドはフィルタが破棄される時に呼び出されます。

The doFilter method of the Filter is called by the container each time a 
request/response pair is passed through the chain due to a client request 
for a resource at the end of the chain. The FilterChain passed in to this 
method allows the Filter to pass on the request and response to the next 
entity in the chain.

Throws: 
  java.io.IOException 
  ServletException

"doFilter"メソッドはFilterインターフェースを実装したフィルタクラスがフィルタとして呼び出された時に実行されるメソッドです。通常のサーブレットのdoGetメソッドやdoPostメソッドに相当します。

よってフィルタとして使うサーブレットは次のような構成になります。

import java.io.*;
import javax.servlet.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;

public class FilterTest implements Filter{
  public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain){

    try{
      /* フィルタで行う処理 */
    }catch (ServletException se){
    }catch (IOException e){
    }
  }

  public void init(FilterConfig filterConfig){
  }

  public void destroy(){
  }
}

"doFilte"メソッド内で、フィルタとして行いたい処理を記述します。

FilterChainインターフェース

先ほどのような構成だと、フィルタが呼び出された後で本来実行されるべきサーブレットに処理を戻していません。1つのフィルタは複数のサーブレットの前処理として共通して利用される場合があり、フィルタがどのサーブレットを実行する途中で呼び出されたのかを知る必要があります。その流れを管理しているのが"doFilter"メソッドの3番目の引数であるFilterChainインターフェースの値です。

FilterChainインターフェースは、どのサーブレットを呼び出そうとした時にこのフィルタが呼ばれ、このフィルタの次に呼び出すべきサーブレットは何かということを管理しています。フィルタの次に別のフィルタがさらに呼び出される場合もありますし、本来の目的のサーブレットが呼び出される場合もありますが、フィルタではあまり意識することなく、FilterChainインターフェースで定義されている"doFilter"メソッドを呼び出すだけで次のサーブレットへ処理を移してくれます。

Causes the next filter in the chain to be invoked, or if the calling 
filter is the last filter in the chain, causes the resource at the end 
of the chain to be invoked. 

Parameters:
  request - the request to pass along the chain.
  response - the response to pass along the chain. 
Throws: 
  java.io.IOException 
  ServletException

※FilterインターフェースとFilterChainインターフェースで同じ名前で定義されている"doFilter"メソッドをそれぞれ使うので注意して下さい。

よってフィルタでは、フィルタ内の処理が終わった段階で"doFilter"メソッドを呼び出すことでフィルタとしての処理を終了します。

import java.io.*;
import javax.servlet.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;

public class FilterTest implements Filter{
  public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain){

    try{
      /* フィルタで行う処理 */

      chain.doFilter(request, response);

    }catch (ServletException se){
    }catch (IOException e){
    }
  }

  public void init(FilterConfig filterConfig) throws ServletException{
  }

  public void destroy(){
  }
}

FilterChainインターフェースの"doFilter"メソッドを呼び出さずに、他のサーブレットへフォワードやリダイレクトしてフィルタの流れを切る事も可能です。例えばフィルタで認証のチェックを行い認証が行われていなければログインを行うサーブレットへリダイレクトするといった処理です。

public void doFilter(ServletRequest request, ServletResponse response,
  FilterChain chain){
    try{
      if (認証が行われている) then{
        chain.doFilter(request, response);
      }else{
        ((HttpServletResponse)response).sendRedirect("/Login");
      }
    }catch (ServletException se){
    }catch (IOException e){
    }
  }
}

サンプルプログラム

では簡単なサンプルプログラムでフィルタを試してみましょう。

今回作成するWebアプリケーションのパスは「filter」とし、Webアプリケーションの置き場所は「d:¥servlet-sample¥filter¥」としました。コンテキストファイルは下記のようになります。

filter.xml

<Context path="/filter"
docBase="d:/servlet-sample/filter"/>

web.xmlファイルは下記のようにしました。

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">

  <filter>
    <filter-name>filtertest</filter-name>
    <filter-class>FilterTest</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>filtertest</filter-name>
    <url-pattern>/helloworld</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>helloworld</servlet-name>
    <servlet-class>HelloWorld</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>helloworld</servlet-name>
    <url-pattern>/helloworld</url-pattern>
  </servlet-mapping>
</web-app>

プログラムは下記の通りです。

HelloWorld.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException{

    response.setContentType("text/html; charset=Shift_JIS");
    PrintWriter out = response.getWriter();

    System.out.println("HelloWorld");

    out.println("<html>");
    out.println("<head>");
    out.println("<title>フィルタテスト</title>");
    out.println("</head>");
    out.println("<body>");

    out.println("<p>Hello World!</p>");

    out.println("</body>");
    out.println("</html>");
  }
}

FilterTest.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;

public class FilterTest implements Filter{
  public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain){

    try{
      System.out.println("フィルタ実行");

      chain.doFilter(request, response);
    }catch (ServletException se){
    }catch (IOException e){
    }
  }

  public void init(FilterConfig filterConfig) throws ServletException{
  }

  public void destroy(){
  }
}

上記をコンパイル後に「d:¥servlet-sample¥filter¥WEB-INF¥classes¥」ディレクトリにクラスファイルを移動した後で、ブラウザで「http://localhost:8080/filter/helloworld」へアクセスしてみます。

Filterテスト

まず呼び出したサーブレットは普通に実行されています。次にフィルタとして設定したサーブレットが実行されているか確認します。

Filterテスト

Tomcatのstdoutログを確認すると、フィルターで記述した標準出力への出力が実行されていることが確認できました。HelloWorldクラスを呼び出すと、HelloWorldクラスが呼び出される前にFilterTestクラスが呼び出されていることになります。

( Written by Tatsuo Ikura )

関連記事 (一部広告含む)