Red > Green > Refactor > Red

cycle is based on desire

struts2 の interceptor とは何か(構築方法含む)

struts2 v2.3.28

実行環境: Mac OSX EI Capitan 10.11.4

interceptor とは何か

action ごと(リクエストごと)に、共通化された前処理を実行したい時がある

(主な例: action 実行前の logging)

この「actionごとの、前処理実行」を実現する手段が interceptor

構築方法

前提環境

projectSpace
|
├── pom.xml
└── src
    └── main
       ├── java
       │   └── jp
       │       └── ymatsukawa
       │           ├── interceptors
       │           │   └── Logger.java
       │           └── top
       │               └── Index.java
       ├── resources
       │   └── struts.xml
       └── webapp
           ├── WEB-INF
           │   └── web.xml
           └── index.jsp

pom.xml

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>jp.ymatsukawa</groupId>
    <artifactId>baseStruts</artifactId>
    <name>Struts2Base</name>
    <description>Struts 2 Base application</description>
    <version>0.0.1</version>

    <packaging>war</packaging>

    <dependencies>
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
      </dependency>
      <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts2-core</artifactId>
        <version>2.3.24.1</version>
      </dependency>
      <dependency>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
      </dependency>
    </dependencies>
    <build>
      <finalName>basic-struts</finalName>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-war-plugin</artifactId>
          <version>2.6</version>
          <configuration>
            <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>jetty-maven-plugin</artifactId>
          <version>9.3.7.v20160115</version>
          <configuration>
            <stopKey>CTRL+C</stopKey>
            <stopPort>8999</stopPort>
            <scanIntervalSeconds>10</scanIntervalSeconds>
          </configuration>
        </plugin>
      </plugins>
    </build>

</project>

src/main/webapp/WEB-INF/web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  "http://java.sun.com/dtd/web-app_2_3.dtd" >

<webapp>
  <display-name>Struts 2 Web Application</display-name>
  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</webapp>

src/main/webapp/index.jsp

<h1>Hello world</h1>

src/main/java/main/jp/ymatsukawa/top/Index.java

package jp.ymatsukawa.top;
import com.opensymphony.xwork2.ActionSupport;

public class Index extends ActionSupport {
  public String execute() {
    return SUCCESS;
  }
}

interceptors の構築方法

まずは struts.xml に手を入れる

src/main/resources/struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
  <constant name="struts.devMode" value="true" />
  <constant name="struts.ui.theme" value="simple" />
  <package name="top" extends="struts-default">
    <interceptors>
      <interceptor name="myLog" class="jp.ymatsukawa.interceptors.Logger" />
    </interceptors>
    <action name="index" class="jp.ymatsukawa.top.Index">
      <interceptor-ref name="myLog" />
      <result name="success">/index.jsp</result>
    </action>
  </package>
</struts>
package.interceptors と package.interceptors.interceptor について

package 下に interceptors を定義

interceptors 下に interceptor を定義

(interceptor 属性) name class
- 必須
一意な識別子
必須
interceptor のロジックが定義された Java クラス
パッケージ名も指定
interceptor を実行する action について

action.interceptor-refname 属性に、実行したい interceptor

package.interceptors.interceptor#name の値を割当

(複数interceptoraction に割当てる場合は

interceptor-ref複数 action 下で定義する

ただし、interceptor は上から順に実行される

下の例だと myLogger, myTest の順 )

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
  <constant name="struts.devMode" value="true" />
  <constant name="struts.ui.theme" value="simple" />
  <package name="top" extends="struts-default">
    <interceptors>
      <interceptor name="myLog" class="jp.ymatsukawa.interceptors.Logger" />
    </interceptors>
    <action name="index" class="jp.ymatsukawa.top.Index">
      <interceptor-ref name="myLog" />
      <interceptor-ref name="myTest" />
      <result name="success">/index.jsp</result>
    </action>
  </package>
</struts>

src/main/java/jp/ymatsukawa/interceptors/Logger.java

package jp.ymatsukawa.interceptors;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.Action;

public class Logger extends AbstractInterceptor {
  public String intercept(ActionInvocation invocation) throws Exception {
    System.out.println("[myLogger:logged] foo"); // think this as logging logic
    return invocation.invoke();
  }
}

実行

console

$ mvn jetty:run
# when got request from browser # GET /top/index.action
[myLogger:logged] foo # interception
# and <h1>Hello world</h1> is rendered by jsp # after interception

他註記

  • interception が実行されるのは action の result が call された後
    • result が call される前に interception を実行したい時は PreResultListener を使う
  • interceptor はスレッドセーフであるべき
    • Struts2 の action は全てスレッドセーフである必要がない
    • interceptor は 全 action 間で共有される
    • 従って interceptor はスレッドセーフでなければいけない

余談

interception での「後片付け」処理

src/main/java/jp/ymatsukawa/interceptors/Logger.java

本モジュール以外は上記掲載通りとする

package jp.ymatsukawa.interceptors;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.Action;

public class Logger extends AbstractInterceptor {
  public String intercept(ActionInvocation invocation) throws Exception {
    try {
      System.out.println("[myLogger:logged] foo"); // think this as logging logic
      return invocation.invoke();   
    } catch(Exception e) {
      System.out.println("[myLogger:logged... error]");
      return Action.ERROR;
    }
  }
}

(interception 実行時 Exceptionthrow された時

catch 句が実行される

トランザクション後処理などに使えそう)


[参考元]

https://struts.apache.org/docs/writing-interceptors.html

https://struts.apache.org/docs/interceptors.html

http://www.benmccann.com/struts-2-tutorial-interceptors/