Help us understand the problem. What is going on with this article?

リクエストパラメータを受けとりたくないフィールドの設定方法(アノテーション編)

More than 1 year has passed since last update.

まえがき

今回はActionクラスのフィールドと、リクエストパラメータの関係についてです。Conventionプラグインも使いますので導入しておいてください。

なお、Struts2では、全てのリクエストに対するパラメータ名を指定したフィルタリングはParametersInterceptorで行いますが、個別Actionクラスでさらにフィルタリングも設定可能です。それがアノテーションでのフィールド設定です。

Actionクラスのフィールドはリクエストパラメータを反映する

例えばリクエストパラメータとして、以下のクエリ文字列の場合を想定します。

name=capybara&phone=09012345678

これに対し、Actionクラスにはnameとphoneフィールドを用意して、get/setメソッドも設置しておきます。lombok使っている場合は省略できますね。

SampleAction.java
public class SampleAction extends ActionSupport {

    @Action("")
    public String start() throws Exception {
        return SUCCESS;
    }

    @Getter @Setter
    private String name;

    @Getter @Setter
    private String phone;
}

このように、リクエストパラメータの名前と同じフィールドがあれば格納されます。

リクエストパラメータに対するフィールドがActionクラスになかった場合

リクエストパラメータに対するフィールドがActionクラスになかった場合は、Struts2の内部ないしは実装したActionクラスには反映されません。例えば先ほどのSampleActionに対し、

name=capybara&phone=09012345678&cityname=tokyo

このクエリ文字列でリクエストしてもcitynameがないため、citynameの内容はActionクラスへは反映されません。

ただしこれはサーブレットリクエストの内容を破棄しているわけではありませんので、HttpServletRequestから復元することは可能です。

受けとりたくないフィールドを設定する方法

Struts2.3.16以降ないしは2.5系では次の設定をします。

  • struts.xmlにてインターセプタ宣言を追加します。
  • リクエストパラメータを受けとりたくないフィールドに@Blockedアノテーションを付与します

…そう、なんとデフォルトの設定では、アノテーション用のインターセプタが有効でなくなりました。
だたし実装されたインターセプタが非推奨になったわけではありませんので、これを設定します。

struts.xml
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    <package name="sample-default" abstract="true" extends="struts-default">
        <interceptors>
            <interceptor name="annotationParams" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationParameterFilterIntereptor"/>

            <interceptor-stack name="sampleStack">
                <interceptor-ref name="exception" />
                <interceptor-ref name="servletConfig" />
                <interceptor-ref name="i18n" />
                <interceptor-ref name="prepare" />
                <interceptor-ref name="scopedModelDriven" />
                <interceptor-ref name="modelDriven" />
                <interceptor-ref name="fileUpload" />
                <interceptor-ref name="checkbox" />
                <interceptor-ref name="multiselect" />
                <interceptor-ref name="actionMappingParams" />
                <interceptor-ref name="annotationParams" />
                <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-stack>
        </interceptors>
        <default-interceptor-ref name="sampleStack"/>
    </package>
</struts>

ポイントは3つです。

  1. AnnotationParameterFilterIntereptorを<interceptor>で宣言し、別名(ここではannotationParams)をつけます。
  2. <interceptor-stack>を作成し、annotationParamsを<interceptor-ref name="params" />よりも手前に差し込みます。
  3. <default-interceptor-ref>またはActionクラスの@InterceptorRefに、<interceptor-stack>で作成したインターセプタスタック(インターセプタの組み合わせ)を設定します。

これでActionクラスのフィールドに対してブロック設定する準備が整いました。

あとはもう簡単で、

SampleAction.java
public class SampleAction extends ActionSupport {

    @Action("")
    public String start() throws Exception {
        return SUCCESS;
    }

    @Getter @Setter
    @Blocked
    private String name;

    @Getter @Setter
    private String phone;
}

こうすると、@blockedで指定したフィールド name には、リクエストパラメータの内容は反映されません。phoneには特にないので反映されます。

Action全体設定もできる

Actionクラスでデフォルト拒否/許可の設定を選べます。Apache HTTPDのDeny ALLやAllow ALLと同様の働きです。

全体拒否

Actionクラスに@BlockByDefaultを付けます。これにより、全てのフィールドに対して一切リクエストパラメータの内容が反映されません。
許可するフィールドのみに@Allowedをつけます。

全体許可(デフォルト)

Actionクラスのフィールドへの格納制限がないのがデフォルトです。拒否したいフィールドに対して@Blockedをつけます。

まとめ

このようにActionクラスごとにもフィールドの受信拒否/許可設定ができます。これによりActionクラスから別の役割と持つフィールドやオブジェクトが同名のリクエストパラメータによって書き換わることは回避されます。

例えば、ActionクラスからSpringのクラスを呼ぶときや、データアクセス担うDAO層のインスタンスを取得していた場合には、この機能を使うことで、リクエストパラメータからの影響は排除されます。

alpha_pz
Struts2とThymeleaf3大好きでプラグインも作ってますよ。お仕事はSpringですけれど。
https://github.com/A-pZ/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away