質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.10%

【Struts2】token interceptorを使ったのですがインターセプタの挙動が理解できません

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,946

score 19

Struts2で二重送信を防ぐために、以下のようにtoken interceptorを使いました。

<action name="TestAction" class="test.action.TestAction" method="execute">
    <interceptor-ref name="token"/>
    <result name="success">xxx.jsp</result>
    <result name="invalid.token">yyy.jsp</result>
</action>


JSPにも<s:token/>を仕込み済みです。

しかし、これでActionを実行してみたところ、1回目のsubmitをした瞬間に「ぬるぽ」が発生してしまいました。

<interceptor-ref name="token"/>を書く前は正常にJSPからActionへ値をsetterで送り込めていました。

そこで、以下のように<interceptor-ref name="defaultStack"/>を書いてみると値を送ることに成功。

<action name="TestAction" class="test.action.TestAction" method="execute">
    <interceptor-ref name="defaultStack"/>
    <interceptor-ref name="token"/>
    <result name="success">xxx.jsp</result>
    <result name="invalid.token">yyy.jsp</result>
</action>

ここで2つの疑問なのですが


なぜ<interceptor-ref name="token"/>を書いた途端にValueStackのActionプロパティに値をセットできなくなり、defaultStackを書いた途端にできるようになったのでしょうか?

<interceptor-ref name="token"/>のようにインターセプタ単品を指定するということは、指定しなかったデフォルトのインターセプタ全てが動作しない。ということを意味するということかと思ったのですが・・・


Actionプロパティに値をセットする役割を持ったインターセプタがいる、ということだと思うのですが、具体的にどのインターセプタがその役割を担っているのでしょうか?

以下サイトを読んで、params interceptorではないかと思いました。

https://www.javatpoint.com/struts-2-interceptors-tutorial

20) params It populates the action properties with the request parameters.

しかし、<interceptor-ref name="params"/>と書いても値が渡らず同じくぬるぽになってしまいました。。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

Struts2のインターセプタは、無設定のときには struts2のjarファイルに含まれる struts-default.xmlの定義にある defaultStack のインターセプタ・スタック(=インターセプタの組み合わせを定義したもの)が使われます。

defaultStackの内容は、以下のとおり、複数のインターセプタを経てActionクラスへのフィールドならびにStruts2内部のOgnlValueStackへ情報が格納されていきます。

            <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="debugging"/>
            </interceptor-stack>

なぜdefaultStackが利用されるかは、同じく struts-default.xml の末の方に書かれている

<default-interceptor-ref name="defaultStack"/>

で定義されているからです。


ではtokenInterceptorはどのように追加するべきかですが、それは defaultStackをカスタマイズしますが、もっと簡単で確実な方法は、 defaultStackの後に tokenInterceptor を後刺し します。

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.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />

    <package name="custom" extends="struts-default">
        <interceptors>
            <interceptor-stack name="tokenStack">
                <interceptor-ref name="defaultStack" />
                <interceptor-ref name="token" />
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="tokenStack"/>
    </package>
</struts>

このstruts.xmlの設定により、struts-default の設定を継承した custom 設定ができ、customのインターセプタスタックで、tokenStack が標準で利用できる準備ができました。


これを使うActionクラスは、例えばConventionプラグインを利用した例では、以下のように @ParentPackage で先ほど作成した custom を指定します。

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;

import com.opensymphony.xwork2.ActionSupport;

@Namespace("/sports")
@ParentPackage("custom")
@Results({
    @Result(name = ActionSupport.SUCCESS, type = "dispatcher", location="sports.jsp")
})
public class SportsAction extends ActionSupport {
  .....
}

@ParentPackageを指定せずActionクラスごとにインターセプタを設定する方法もあります。そのときは@InterceptorRefsを利用します。

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.InterceptorRef;
import org.apache.struts2.convention.annotation.InterceptorRefs;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;

import com.opensymphony.xwork2.ActionSupport;

@Namespace("/sports")
@InterceptorRefs({
    @InterceptorRef("defaultStack"),
    @InterceptorRef("token"),
})
@Results({
    @Result(name = ActionSupport.SUCCESS, type = "dispatcher", location="sports.jsp")
})
public class SportsAction extends ActionSupport {
    ....
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/17 15:52

    ご回答ありがとうございます!
    struts.xmlでインターセプタをカスタマイズせず特定の<action>の中に<interceptor-ref name="token"/>だけを直に書くと、そのAction実行時はデフォルト含めその他のインターセプタが全て機能しなくなる、という理解で良いでしょうか?

    キャンセル

  • 2018/11/17 16:09

    はい、その通りです。

    tokenInterceptorだけが動く状態になってしまいます。公式サイトには特に書かれていないのですが、Struts2はすべてのインターセプタが basicStack と名付けられた最低限のインターセプタが搭載されている前提で動作しますので、もしこれを除外をしてしまうと、誤動作や例外が出てしまいます。

    キャンセル

  • 2018/11/19 11:48

    > tokenInterceptorだけが動く状態になってしまいます。
    理解しました!ありがとうございます!!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る