Red > Green > Refactor > Red

cycle is based on desire

struts.xml interceptor-stack 要素とは何か

interceptor-stack 要素とは何か

interceptors.interceptor をひとまとまり に定義したもの

利用により、汎用的に interceptorinterceptor-ref で参照できる

具体的に

下記 struts.xml より

  • interceptor が
    • ロギング
    • DB コネクション処理

の 2 つで定義されているとする

<?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="myLogging" class="jp.ymatsukawa.interceptors.Logger" />
      <interceptor name="myDBConnection" class="jp.ymatsukawa.interceptors.DBConnection" />
    </interceptors>
    <action name="index" class="jp.ymatsukawa.top.Index">
      <interceptor-ref name="myLogging" />
      <interceptor-ref name="myDBConnection" />
      <result name="success">/index.jsp</result>
    </action>
  </package>
</struts>

action が新規追加されるごとに action#name="index"

interceptor-ref がコピペされそうである

汎用的に これらまとまり(interceptors.interceptor) を参照できる形式にしよう

<?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="myLogging" class="jp.ymatsukawa.interceptors.Logger" />
      <interceptor name="myDBConnection" class="jp.ymatsukawa.interceptors.DBConnection" />
      <interceptor-stack name="myStackDBCon">
        <interceptor-ref name="myLogging" />
        <interceptor-ref name="myDBConnection" />
      </interceptor-stack>
    </interceptors>
    <action name="index" class="jp.ymatsukawa.top.Index">
      <interceptor-ref name="myStackDBCon" />
      <result name="success">/index.jsp</result>
    </action>
  </package>
</struts>

struts.package.interceptors.interceptor の下に

  • interceptor-stack を追加
  • interceptor-stack#name に 各 actioninterceptor-ref が参照する名前を命名

[参考元]

https://struts.apache.org/docs/interceptors.html#Interceptors-StackingInterceptors

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/

struts.xml の struts.action と struts.action.result 要素

struts.action について

(属性値の入力) name class
- 必須
(パッケージ内で一意)
任意
(入力の場合は存在する Java クラスを
package 名付きで割当)

(X)

<struts>
  <package name="top" namespace="/" extends="struts-default">
    <action name="actionName" class="jp.co.pckg.to.ActionCallerClass">
    </action>
  </package>
</struts>

Struts2 には "action mappings" という機能があり、

action は Java クラスをハンドルする為に識別子をマッピングする

リクエストが action名 と合致した時、Struts2 はこのマッピングを利用して

どのプロセスを実行すべきかを決定する

(X) の場合

actionName という識別子を持ち、ハンドルするクラスは jp.co.pckg.to.ActionCallerClass

である

class 属性は省略可(Y)

struts.action.result について

(属性値の入力) name type
- 任意
(属性を指定しない場合は自動で
name="success")
任意
(属性をしていない場合は自動で
type="dispatcher")
<struts>
  <package name="top" namespace="/" extends="struts-default">
    <action name="actionName" class="jp.co.pckg.to.ActionCallerClass">
      <result name="success">/index.jsp</result>
    </action>
    </action>
  </package>
</struts>

ハンドルクラスの execute メソッド

result の name 属性で指定した値(String) をレスポンスとして返す必要がある(Z)

返さない場合はサーバーエラー(動作確認より)

また、レスポンスの種類(type) を指定できる

struts.action, struts.action.result を用いて

/index.action へ GET リクエストすると

jp.co.pckg.to.ActionCallerClassexecute() が実行され

/index.jsp が dispatch される


(Y) の場合

つまり

(<action name="actionName" class="jp.co.pckg.toActionCallerClass">)

ではなく

(<action name="actionName")

の時

/index.jsp が render されるだけ

(Z) ActionSupport クラスで定義済の値一覧

String SUCCESS = "success"
String NONE    = "none",
String ERROR   = "error"
String INPUT   = "input"
String LOGIN   = "login"

これら以外で result.name の値を指定しても良い

(今回は省略)


[転載、及び引用元]

https://struts.apache.org/docs/result-configuration.html

https://struts.apache.org/docs/action-configuration.html#ActionConfiguration-Post-BackDefault

struts.xml の struts.package 要素

struts2.3.28

struts.package とは

要素 actions, results, reult types, interceptors, interceptor-stacks

を一論理グループにまとめる要素

「拡張ができて、サブパッケージで個々のパーツをオーバーライドができるオブジェクト」

と思えば良い

Packages are a way to group actions, results, result types, interceptors, and interceptor-stacks into a logical configuration unit.
Conceptually, packages are similiar to objects
in that they can be extended and have individual parts
that can be overridden by "sub" packages.

抜粋元

package の属性と必須/任意

抜粋元は同上

要素 必須/任意 概要
name yes 他パッケージが参照するときのキー名
extends no 他 package を継承する時、その package 名を割当てる
namespace no 名前空間(A)
abstract no 抽象パッケージの指定(未精査:いつ使う?)

(A)

URI ルーティングの意味合いでは

localhost:8080/namespace/strutsAction

namespace に該当する

  1. namespace を指定しない場合はブランクであり、"/" にならない(動作確認より)

  2. namespace="" を指定すると "/" と同値になる

【整理中】

  1. について

url-pattern 要素 を /* に指定している場合

strutsAction に対して namespace に期待外の文字列が入り得る(動作確認より)

ので Y. 明示的に "" の指定が必要と考えられる

例えば

localhost:8080/./strutsAction

localhost:8080/$/strutsAction

は 503 レスポンスを返さず strutsAction を実行する

(action 要素記載時に詳細記載予定)

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

参考元:

https://struts.apache.org/docs/package-configuration.html

struts.xml の struts.constant 要素

struts.constant とは

Struts2 がデフォルトで設定している要素を上書きする要素

Constants provide a simple way to customize a Struts application
by defining key settings that modify framework and plugin behavior.

抜粋元

デフォルトの要素とその値一覧はどこでわかるか

公式Doc

日本語はこちら

<struts>
  <constant name="struts.ui.theme" value="simple" /> <!-- struts のテーマを使わない(A) -->
  .
  .
</struts>

(A) 参考情報

https://struts.apache.org/docs/themes-and-templates.html