[Servlet]「ServletContextListenerインターフェース」(リスナー)の実装〜フィルターの呼び出し順序指定クラス〜

2022/06/18に公開


◆はじめに

ServletContextListenerインターフェース(以下:リスナー)を実装することで、
複数のFilterに対して指定した順序で呼び出すことが可能です。
その方法について、お伝えいたします。


◆リスナーについて

Filterクラスを実装した際に、
複数のFilterを呼び出す際に、呼び出す順序を指定したい場合があるとします。
その場合、以下の2つの方法があります(他にもあるかもしれませんが)


①ServletContextListenerインターフェース(通称リスナー)による方法

②@WebFilterアノテーションで呼び出し、web.xmlに呼び出す順序を記述する方法


今回は、②の方法で実装する場合について、
事前に準備してあるプロジェクトをベースにご紹介します。
次のトピックをご覧ください。


◆前提/環境など

本記事は、以下の記事の「InputFunction」プロジェクトをベースに作成しています。
Echo機能のServletの処理時間を計測するFilterを実装しています。
以下の記事の内容を踏まえた前提で、記事は書いていますのでご了承ください。

https://zenn.dev/nakohama/articles/5ba42253eddef1


ただ、もし既にServletとFileterを実装しているプロジェクトがあるならば、
基本的には、そのプロジェクトにListerのクラスを実装するだけで、可能だと思います。
呼び出すフィルターの名前だけ変更のみで、あとは手順のコードのコピペで大丈夫です。


※本記事では、 eclipseは以下のバージョンでの画像を使用しています。
日本語化はしていません。
他のversionでの動作は確認しておりません。


◆手順

「InputFunction」プロジェクトからの
変更箇所と追加箇所をメインに記載しています。


また、「InputFunction」プロジェクトの「TimeFilter.java」に記述していた
@WebFilterアノテーションは使用する必要はないため、
予め、コメントアウトしておきましょう。
TimeFilter.java
~~~省略~~~

//@WebFilter("/echo")
public class TimeFilter implements Filter{

~~~省略~~~


①FilterRegisterクラスの用意

・mainフォルダに「listener」のパッケージを作成
・「listener」のパッケージ内に、「FilterRegister.java」を作成


②リスナーのソースコード

・以下のコードを、「FilterRegister.java」に記述
FilterRegister.java
package listener;

import java.util.EnumSet;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

import filter.TimeFilter;

@WebListener
public class FilterRegister implements ServletContextListener{
	
	@Override
	public void contextInitialized(ServletContextEvent servletContextEvent) {
		
		System.out.println("START FilterRegister#contextInitialized()");
		
		ServletContext context = servletContextEvent.getServletContext();
		
		//呼び出すFilterの登録
		addFilter(context , "TimeFilter" , TimeFilter.class, "/echo" );	
//複数Filterを順序を指定して呼び出す際は、呼び出す順番で以下にaddFilter()を追記
//addFilter(context , "フィルターのクラス名" , フィルターのクラス名.class, "URL" );
		
		System.out.println("END FilterRegister#contextInitialized()");
	}
	
	private void addFilter(ServletContext context, String filterName , Class<? extends Filter> filterClass , String... urlPatterns) {
		
		context.addFilter(filterName, filterClass);
		
		FilterRegistration filterRegistration = context.getFilterRegistration(filterName);
		
		EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST , DispatcherType.FORWARD );
		
		filterRegistration.addMappingForUrlPatterns (dispatcherTypes , false , urlPatterns);
	}
	
	@Override
	public void contextDestroyed(ServletContextEvent servletContextEvent) {
		
	}
}


そして、複数Filterを順序を指定して呼び出す際には、
以下の箇所に、呼び出したい順番で、
addFilter()を使用して追記してください。
~~~省略〜〜〜

addFilter(context , "TimeFilter" , TimeFilter.class, "/echo" );
//複数Filterを順序を指定して呼び出す際は、呼び出す順番で以下にaddFilter()を追記
//addFilter(context , "フィルターのクラス名" , フィルターのクラス名.class, "URL" );

~~~省略〜〜〜


「InputFunction」プロジェクトでは、以上でソースを貼った以外の
ファイルのコードや追加しているライブラリーに関しては、特に変更はありません。
そちらのソースに関しては、以下の記事をご参照ください。

https://zenn.dev/nakohama/articles/5ba42253eddef1


③動作チェック

・Tomcatなどアプリケーションサーバーを起動
・実装後に以下のURLにアクセス

http://localhost:8080/InputFunction/echo.jsp

以下の画面が表示されるので、
・テキストボックス文字列を入力
・送信ボタンを押す

Echo機能の仕様は以下です。
・文字列を入力し、送信ボタンを押す。
・Echo機能を提供するServletが呼び出される。
・送信した文字列が、再度、画面に表示される。


因みに、Validation機能の使用は以下です。
・送信された文字列が空欄の場合は、
「この項目は必須入力です。」と文字列が表示される。

そして、正常にTimeFilerが動作していれば、
Eclipseのコンソールに、
計測されたServletの処理時間が表示されているはずです。

以上です。


◆おまけ(②@WebFilterアノテーションでweb.xmlで記述する方法)

「◆はじめに」でご紹介した、

②@WebFilterアノテーションで呼び出し、web.xmlに呼び出す順序を記述する方法

の場合のコードも載せておきます。


web.xml
<web-app>
	~~~省略〜〜〜
	
	<!--最初に呼び出すフィルター -->
 <filter>
    <filter-name>TimeFilter</filter-name>
    <filter-class>filter.TimeFilter</filter-class>
  </filter>
  <filter-mapping>
   <filter-name>TimeFilter</filter-name>
   <url-pattern>/*</url-pattern>
  </filter-mapping> 
	
	<!--以下、同様の書き方で、呼び出す順番にフィルターを記載 -->
		
	~~~省略〜〜〜
	
</web-app>


◆さいごに

以上です。いかがだったでしょうか。
リスナーの実装はできたでしょうか。
今回のポイントです。


①FilterRegisterクラスを作成する

②addFilter()を使用して、呼び出す順序でフィルターを記載

③フィルターのクラスに @WebFilterアノテーションは不要


コードに関しての詳しい説明に関しては、
あまり書いていません。少し、コード内にコメントはつけてます。
あとは、他の参考に載せている書籍やサイトなど調べてみてください。


最後まで、ご覧いただきありがとうございました。


◆参考

本記事は、以下の書籍を大いに参考にしています。
より詳しく知りたい方は、どうぞ。

https://www.amazon.co.jp/dp/4797362596

・関連記事、その他

Discussion