struts.xml default-interceptor-ref 要素とは何か
default-interceptor-stack 要素とは何か
package
内で定義した interceptor-stack
の内
package
の各アクションにてデフォルトで参照させたい
interceptor
を定義する
具体的に
下記 struts.xml より interceptor-stack
に ロギングが定義されている
(action はまだ 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-stack name="myStackLogging"> <interceptor-ref name="myLogging" /> </interceptor-stack> </interceptors> <action name="index" class="jp.ymatsukawa.top.Index"> <result name="success">/index.jsp</result> </action> </package> </struts>
全 action
で package.interceptors.interceptor-stack#name="mystackLogging"
が参照されることになったので default-interceptor-ref
を使い、目的を達成する
<?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-stack name="myStackLogging"> <interceptor-ref name="myLogging" /> </interceptor-stack> </interceptors> <default-interceptor-ref name="myStackLogging" /> <action name="index" class="jp.ymatsukawa.top.Index"> <result name="success">/index.jsp</result> </action> </package> </struts>
interceptors
を定義した後に
default-interceptor-ref#name="共通参照したい interceptor-stack"
を定義する
action
要素の下には interceptor-ref
の記載は入れない
default-interceptor-ref 定義後に
各 action で interceptor-ref を定義した時の挙動
default-interceptor-ref
を定義した後、各 action
で
interceptor-ref
を定義するとどうなるか
先に要約すると default-interceptor-ref
は実行されず
各 action
で定義された interceptor-ref
が実行される
<?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="myOtherLogging" class="jp.ymatsukawa.interceptors.OtherLogger" /> <interceptor-stack name="myStackLogging"> <interceptor-ref name="myLogging" /> </interceptor-stack> </interceptors> <default-interceptor-ref name="myStackLogging" /> <action name="index" class="jp.ymatsukawa.top.Index"> <interceptor-ref name="myOtherLogging" /> <result name="success">/index.jsp</result> </action> </package> </struts>
default-interceptor-ref(myLogging)
> action.interceptor-ref(myOtherLogging)
が実行されると思いきや
action.interceptor-ref(myOtherLogging)
のみ実行される
[参考元]
https://struts.apache.org/docs/how-do-we-configure-an-interceptor-to-be-used-with-every-action.html
struts.xml interceptor-stack 要素とは何か
interceptor-stack 要素とは何か
interceptors.interceptor
をひとまとまり に定義したもの
利用により、汎用的に interceptor
を interceptor-ref
で参照できる
具体的に
- 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
に 各action
のinterceptor-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 の構築方法
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-ref
の name
属性に、実行したい interceptor
を
package.interceptors.interceptor#name
の値を割当
(複数の interceptor
を action
に割当てる場合は
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
を使う
- result が call される前に interception を実行したい時は
- 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
実行時 Exception
が throw
された時
catch
句が実行される
トランザクション後処理などに使えそう)
[参考元]
https://struts.apache.org/docs/writing-interceptors.html
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.ActionCallerClass
の execute()
が実行され
/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
に該当する
namespace
を指定しない場合はブランクであり、"/"
にならない(動作確認より)namespace=""
を指定すると"/"
と同値になる
【整理中】
- について
url-pattern 要素 を /*
に指定している場合
strutsAction に対して namespace に期待外の文字列が入り得る(動作確認より)
ので Y. 明示的に ""
の指定が必要と考えられる
例えば
localhost:8080/./strutsAction
localhost:8080/$/strutsAction
は 503 レスポンスを返さず strutsAction を実行する
(action 要素記載時に詳細記載予定)
例
<struts> <package name="uniqueNameYouNamed" namespace="/routingPath" extends="struts-default"> </package>
参考元: