Struts2をやってみる (11) - Interceptor -

2013-09-23T00:00:00+00:00 Java Struts2

Interceptorの利用法は今まで何度と無く書いてきたので(ry

とりあえず自分でInterceptorを作って利用してみる

要件として

package sample.service;

public interface ServiceAware<T> {
    public void setService(T service);
}

的なインターフェースがあって

package sample.action;

import sample.service.SampleService;
import sample.service.ServiceAware;

import com.opensymphony.xwork2.ActionSupport;

public class IndexAction extends ActionSupport implements ServiceAware<SampleService> {

    private static final long serialVersionUID = 1L;
    private SampleService service;

    public void setService(SampleService service) {
        this.service = service;
    }

    public SampleService getService() {
        return service;
    }
}

的な感じでインターセプターからsetServiceを通じてアクションが発生する前に注入してやる的な事をやってみる

SampleInterceptor.java

package sample.interceptor;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

import sample.service.SampleService;
import sample.service.ServiceAware;

public class SampleInterceptor extends AbstractInterceptor {

    private static final long serialVersionUID = 1L;

    @SuppressWarnings("unchecked")
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Action action = (Action)invocation.getAction();

        if (action instanceof ServiceAware) {
            ((ServiceAware<sampleService>)action).setService(new SampleService());
        }

        System.out.println("before: " + action.toString());

        // ActionInvocation#invokeActionOnlyをすると他のインターセプターを無視してアクション実行されるっぽい
        String result = invocation.invoke();

        System.out.println("after: " + action.toString());

        return result;
    }
}

セッターメソッドを定義しておけばstruts.xmlで<param name="">を利用して値を設定したりとかも出来る

struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <constant name="struts.devMode" value="true" />

    <package name="sample" extends="struts-default" namespace="/sample">

        <!-- 作ったインターセプターを定義 -->
        <interceptors>
            <interceptor name="sample" class="sample.interceptor.SampleInterceptor" />
        </interceptors>

        <action name="index" class="sample.action.IndexAction" method="input">
            <interceptor-ref name="sample" />
            <result name="input">/WEB-INF/jsp/index.jsp</result>
        </action>

    </package>
</struts>

以上。特にややこしい事をやってる訳でもないので

インターセプターをテスト

普通にActionProxy#executeをするとインターセプターも通る。でインターセプターなクラスを単体でテストしたい時とか

package sample.interceptor;

import org.apache.struts2.StrutsTestCase;
import org.junit.Test;

import sample.action.IndexAction;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.interceptor.Interceptor;

import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;

public class SampleInterceptorTestCase extends StrutsTestCase {

    ActionInvocation invocation;
    IndexAction action;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        ActionProxy proxy = getActionProxy("/sample/index.action");
        invocation = proxy.getInvocation();
        action = (IndexAction)proxy.getAction();
    }

    @Test
    public void test_intercept() throws Exception {
        Interceptor interceptor = new SampleInterceptor();
        assertThat(interceptor.intercept(invocation), is(ActionSupport.INPUT));

        assertThat(action.getService(), notNullValue());
    }
}

でさっきコメントで書いたけど、invokeActionOnlyで無い場合だと上記のテストではSampleInterceptorが2回通る。既にインターセプタースタックに載ってる状態で更にインターセプターを追加しちゃってるからだと思われるのだけど

んまぁアクションが実行されるかされないかを許容しないのであれば別にMockActionInvocationでやれば良いだけかと

Struts2をやってみる (12) - Spring Framework - cat - な件