はじめに
「Apache Struts」(以下、Struts)とは、サーバサイドJava開発のデファクトスタンダードとしてあまりにも有名な、オープンソースのWebアプリケーションフレームワークです。本連載では、そのStrutsの次世代バージョンであるStruts 2を、実際に動作するアプリケーションと共に解説していきます。
第4回目の本稿は、Struts 2の「インターセプター」という仕組みを取り上げることにします。
前回の記事
- Struts 2入門(1)~基本形で理解する仕組みと構造~
- Struts 2入門(2)~バリデーションの仕組みを理解する(前編)~
- Struts 2入門(3)~バリデーションの仕組みを理解する(後編)~
対象読者
サーバサイドJava(JSP&サーブレット)について基本的なことは理解している方を対象とします。
インターセプター
前回と前々回では、主にバリデーション処理を解説しました。そのなかで、Struts 2でのバリデーション処理は、Action
メソッドが呼び出される前に自動的に実行されると説明しました。
じつは、自動的に実行される処理こそがインターセプターで、バリデーションもインターセプターの一つなのです。
インターセプターとは
アメリカンフットボールの用語に、「インターセプト」があります。パスしたボールが守備側に横取りされることをいうのですが、Struts 2のインターセプターも、アメフトと同じようなイメージです。Action
メソッドが呼び出される前に、複数のインターセプターが割り込み、制御を横取りして実行されます。
図中の、ActionProxy
、ActionInvocation
、Result
は、Struts 2の核となるオブジェクトです。Servletコンテナからのリクエストがあると、(図ではActionProxy
が呼ばれる前の処理を省略しています)設定に従ってActionProxy
がインターセプターを呼び出します。インターセプターは、ActionInvocation
オブジェクトがインスタンスを保持しています。
インターセプターは、その処理のなかで再帰的に次のインターセプターを呼び出します。最後のインターセプターの後は、Action
が実行され、Result
オブジェクトで結果画面の生成をします。それから再び呼び出したインターセプターに制御が戻ってきます。そのときの順番は、最初の逆準となり、図の例では、Interceptor3→Interceptor2→Interceptor1という具合になります。
Struts 2では、その機能の多くがインターセプターとして提供されており、さまざまなインターセプターがあらかじめ用意されています。また、プラグインのように、必要に応じてインターセプターを利用することができます。
このようなアプローチは、アスペクト指向と言えるものです。インターセプターにより、Actionクラスを横断するような汎用的な処理をモジュール化することができます。その結果、Actionクラスは固有の処理に特化できるようになり、Actionクラスとしての役割がシンプルに記述できるようになっています。
定義済みのインターセプターは結構数がそろっているものの、当然Webアプリケーション独自のものを定義したい場合があるでしょう。そんな場合は、インターセプターを自分で記述することができます。本稿では、かんたんなインターセプターを作って、インターセプターの動作を明らかにしていきます。
インターセプター名 | 定義名 | 概要 |
Alias インターセプター | alias | 入力画面のフォームのパラメータ名に別名をつける |
Chaining インターセプター | chain | プロパティの内容を次のActionに引き継ぐ |
Checkbox インターセプター | checkbox | フォームのCheckboxで、checkされていなくても、値がセットされるようにする |
Cookie インターセプター | cookie | cookieデータを管理する |
Conversion Error インターセプター | conversionError | 入力フォームの変換エラーを検出する |
Create Session インターセプター | createSession | セッション情報を作成する |
Debugging インターセプター | debugging | デバッグメッセージを表示する |
Execute and Wait インターセプター | execAndWait | 非同期でActionを実行する |
Exception インターセプター | exception | 例外がスローされたときの処理を設定する |
File Upload インターセプター | fileUpload | ファイルのアップロードを支援する |
I18n インターセプター | i18n | ロケール情報を保持する |
Logger インターセプター | logger | ログ出力を行う |
Message Store インターセプター | store | メッセージの保存と参照を行う |
Model Driven インターセプター | modelDriven | Actionをモデルドリブンで操作する |
Scoped Model Driven インターセプター | scopedModelDriven | Actionをスコープドモデルドリブンで操作する |
Parameters インターセプター | params | リクエストパラメータを制御する |
Prepare インターセプター | prepare | Actionクラスのexecute()メソッドが実行される前に呼び出したい処理を記述する |
Scope インターセプター | scope | Actionクラスのプロパティをsessionやapplicationスコープとして設定する |
Servlet Config インターセプター | servletConfig | session等に情報を保存する |
Static Parameters インターセプター | staticParams | Action単位で静的パラメータを定義する |
Roles インターセプター | roles | JAAS認証時のみActionを実行するようにする |
Timer インターセプター | timer | Actionクラスの実行時間を計測する |
Token インターセプター | token | 2重POSTの禁止処理(リクエスト単位)を行う |
Token Session インターセプター | tokenSession | 2重POSTの禁止処理(セッション単位)を行う |
Validation インターセプター | validation | バリデーション処理を行う |
Workflow インターセプター | workflow | validateメソッドの呼び出しを行う |
Parameter Filter インターセプター | parameterFilter | パラメータの取り消しを行う |
Profiling インターセプター | profiling | プロファイリング機能のON/OFF設定をする |
デフォルトのインターセプター
バリデーション処理では、実装さえすれば、特に呼び出し処理を記述する必要はありませんでした。それは、デフォルトで呼び出されるインターセプターがあり、バリデーションもその一つだからです。
あらかじめ用意されているインターセプターの定義は、デフォルトの設定ファイルのstruts-default.xmlにあります。そこで定義されているインターセプターは30ほどあり、そのうちの半数ほどが、デフォルトのインターセプターとして実行されるようになっています。デフォルトのインターセプターは、多くのアプリケーションで必要となる機能を定義したものです。ちょっとしたアプリケーションなら、デフォルトのインターセプターを変更したり、別のインターセプターを追加したりする必要はないでしょう。
なお、設定ファイルのstruts-default.xmlとは、struts.xmlで「extends="struts-default"」と指定して読み込んでいるデフォルトの設定ファイルのことです。
以下が、struts-default.xmlで、デフォルトのインターセプターを定義している箇所です。
<interceptor-stack name="defaultStack"> <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="prepare"/> <interceptor-ref name="i18n"/> <interceptor-ref name="chain"/> <interceptor-ref name="debugging"/> <interceptor-ref name="profiling"/> <interceptor-ref name="scopedModelDriven"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="params"> <param name="excludeParams">dojo\..*</param> </interceptor-ref> <interceptor-ref name="conversionError"/> <interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="workflow"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> </interceptor-stack>
インターセプターに関する設定タグについては、あらためて後述しますが、<interceptor-stack>
タグで、インターセプターをグルーピングしています。ここでは、defaultStackというインターセプターのグループ名を指定しています。また、<param name="excludeMethods">
とは、指定されたメソッドの場合、そのインターセプターを実行しないという意味です。
アスペクト指向(Aspect-oriented)とは、オブジェクト指向の問題点を補うために考案された概念です。オブジェクト指向ではうまく表現できない、クラス間を横断するような機能を「アスペクト(英単語としては、外観や様相といった意味)」とみなし、そのアスペクトをモジュール化するプログラミング技法を、アスペクト指向プログラミング(AOP)と呼びます。
まさにインターセプターとは「アスペクト」であり、Struts 2では、インターセプターという手法でアスペクト指向プログラミングを実装していることになります。