独自のインターセプター
では、かんたんなインターセプターを作ってみましょう。自作したインターセプターで動きを確かめてみます。
Interceptor本体
インターセプター本体は、com.opensymphony.xwork2.interceptor.Interceptorインターフェイスを実装する必要があります。Interceptorインターフェイスには、下記のように3つのメソッドが定義してあり、すべて実装しなければなりません。
ただし、com.opensymphony.xwork2.interceptor.AbstractInterceptorというクラスで、Interceptorインターフェイスのinitメソッドとdestroyメソッドが実装されています。内容のない空のメソッドが定義されているだけですが、これを継承してインターセプターを作ると、不要な実装を記述する手間が省けます。
public interface Interceptor extends Serializable {
void destroy();
void init();
String intercept(ActionInvocation invocation) throws Exception;
}
void init()
Servletコンテナ(Tomcat)を起動すると呼ばれます。
void destroy()
Servletコンテナの終了時に呼ばれます。
String intercept(ActionInvocation invocation)
このメソッドに、インターセプターの処理を記述します。パラメータのActionInvocationオブジェクトを使って、リクエストパラメータやセッションにアクセスします。
ActionInvocationオブジェクトは、Actionクラスを実行したときのステータス情報を格納しており、Actionとインターセプターのインスタンスも保持しています。
例えば、 次のようなコードでリクエストパラメータやセッションや取得することができます。
// セッションの取得
// Struts 2では、Mapオブジェクトとしてセッションが取得できる
Map<String, String> session = ActionContext.getContext().getSession();
// HttpServletRequest、HttpSessionの取得
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = ServletActionContext.getRequest().getSession();
com.opensymphony.xwork2.ActionContextとは、セッション、リクエストパラメータ、ロケール情報などを保持するクラスで、org.apache.struts2.ServletActionContextは、ActionContextの派生クラスです。
詳細は、オンラインのドキュメントを参照してください。これらのオブジェクトを利用して行えるのは、セッションやリクエストパラメータの取得、Actionオブジェクトの名前の参照、結果コードの参照や変更などです。
Interceptorのサンプルコード
以下は、AbstractInterceptorを継承したインターセプターの例です。このクラスを、連載で使用しているサンプルプロジェクトに組み込んでみましょう。
package part4;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class SimpleInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 1L;
// インターセプターの処理(コンソールに文字列を出力する)
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("intercept処理");
// 次のインターセプター処理
String result_code = invocation.invoke();
// Result後のインターセプター処理
System.out.println("intercept処理2");
return result_code;
}
}
このインターセプターは、コンソールに文字列を出力するだけのものです。interceptメソッドの最後で、次のインターセプター処理を継続するために、invocation.invoke()メソッドを呼んでいます。そのメソッドを呼び出さず、Actionクラスと同様に、直接、"success"などの結果のコードを返すことができます。その場合は、直後のActionクラスの実行もスキップされることになります。
なお、invocation.invoke()から戻ってきた後は、結果の処理も終わっています。この例では、結果の画面が表示されてから、二度目のSystem.out.printlnの出力処理を行っています。
次に、設定ファイルのstruts.xmlを変更します。
<interceptors>
<!-- interceptorの定義 -->
<interceptor name="simple" class="part4.SimpleInterceptor"/>
<!-- interceptorをグルーピング -->
<interceptor-stack name="simpleInterceptorStack" >
<!-- 呼び出したい順にinterceptorを記述する -->
<interceptor-ref name="simple" />
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<action name="Hello" class="part1.Hello">
<!-- interceptorの指定 -->
<interceptor-ref name="simpleInterceptorStack"/>
<result name="success">/index.jsp</result>
</action>
<interceptors>~</interceptors>タグ間で、インターセプターの定義をします。そして、<interceptor>タグのname属性で名称、class属性で、インターセプター本体のクラスを指定します。
前述したように、<interceptor-stack>タグはインターセプターのグルーピング指定です。複数のインターセプターをまとめて定義することができます。
Actionクラスごとに指定するインターセプターは、デフォルトのインターセプターとの差分だけという指定ができないので、基本的には常にデフォルトのインターセプター(struts-default.xmlで指定されたdefaultStack)も指定する必要があります。通常、複数のインターセプターを指定することになりますので、グルーピングの設定をしておくと、Actionに適用するインターセプターを1つのグループ名で指定できるようになります。
<action>タグ内の<interceptor-ref>タグで、そのActionに適用するインターセプターを指定します。この指定がない場合は、defaultStackが指定されたことになります。
なお、すべてのActionに適用する場合は、defaultStack自体のグルーピングをstruts.xmlにて上書き設定するか、<default-interceptor-ref>タグを使って、デフォルトのインターセプターを再定義するとよいでしょう(<default-interceptor-ref>タグを使う例は、後述します)。
さっそく、Eclipseからこのアプリケーションを実行して、「こんにちは」のリンクをクリックしてください。次のように、Eclipseのコンソールに、intercept処理とintercept処理2という文字列が、出力されるはずです。
intercept処理 .... intercept処理2
Actionが実行された後のインターセプター
Actionが実行された後(Resultオブジェクトが処理をする前)にも、インターセプターのメソッドを呼び出すことができます。これは、Action結果のコードを判断して、何らかの処理を行いたい場合や、強制的に結果コードを変更したいときに利用できます。
Actionの後に実行するメソッドは、次のように、ActionInvocationクラスのaddPreResultListenerメソッドを用いて設定します。
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("intercept処理");
invocation.addPreResultListener(
new PreResultListener() {
public void beforeResult(ActionInvocation actioninvocation, String resultCode) {
System.out.println("Result:"+resultCode);
}
}
);
// 次のインターセプター処理
String result_code = invocation.invoke();
// Result後のインターセプター処理
System.out.println("intercept処理2");
return result_code;
}
com.opensymphony.xwork2.interceptor.PreResultListenerは、beforeResultメソッドのみを定義したインターフェイスです。beforeResultメソッドが、コールバックとして実行されることになりますので、ここに処理を記述します。
beforeResultメソッドには、Actionの結果コードがパラメータで渡されます。上記のコード例は、その結果コードをコンソールに出力するものです。
