05.Spring-Struts2の実際の利用サンプル
(無設定(ゼロコンフィグ)による構築)

概要

前回の記事では、設定ファイルによるStruts2とSpringの利用サンプルを見ました。

今度は同じ動作内容で、無設定によるサンプルを見てみます。

このサンプルを見る前に、必ず、以前の章の記事をお読みください。

少なくともこちらはお読みください。

目標

ゴールは、設定ファイルによるサンプルと同じです。同じゴールに対してどのように作成方法が変わるかを見て行きます。

ですのでまずは、設定ファイルのサンプルの記事の目標をお読みください。

基本的に、設定ファイルによる方法と同じクラスや設定ファイルを使用します。

ですのでまずはクラスとファイルを上記の記事のリンクからすべてコピーしてください。

ここでは、修正点のみ記述してみようと思います。

修正点のみ記述することで、違いが明確になるかと思います。

使用サンプル

<画面処理(Action)サンプル: test.actions.UserUditAction>

@Scope(BeanDefinition.SCOPE_PROTOTYPE)

public class UserEditAction extends ActionSupport {

@Resource

private UserService userService;

//画面情報の保持---------------------------------------------

private User user;

private String remarks;

public User getUser() {

return user;

}

public void setUser(User user) {

this.user = user;

}

public String getRemarks() {

return remarks;

}

public void setRemarks(String remarks) {

this.remarks = remarks;

}

private List<User> userList;

public List<User> getUserList() {

return userList;

}

public void setUserList(List<User> userList) {

this.userList = userList;

}

//Actionの処理------------------------------------------------

@org.apache.struts2.convention.annotation.Action("/userEdit")

@SkipValidation

public String doInput() throws Exception {

//値を取得する。

User user = this.userService.getUser();

this.user = user;

//結果コードを返す

return Action.INPUT;

}

public String doCert() throws Exception {

//結果コードを返す

return "cert";

}

public String doFinish() throws Exception {

userService.updateUser(this.user);

//結果コードを返す

return "finish";

}

}

【変更点】

doInput()メソッドの前のアノテーションを見てください。

Actionアノテーションを追加しました。

これは、以前の記事で、struts.xmlファイルで、actionタグのmethod属性に記述していた内容を実現するためです。

設定ファイルの方法(以前の記事)でのactionタグの引用:

<action name="userEdit" class="userEditAction" method="doInput">

method属性は、デフォルトでActionクラス内のどのメソッドを実行するかを指定します。

上記のActionアノテーションは、URLとActionのメソッドのマッピングをします。

"/userEdit.action"というURLで、メソッド指定がない場合、doInput()メソッドを実行することになります。

【URLとActionの自動マッピング】

実は、無設定の方法を使用すると、パッケージまで含めたクラス名(例:test.actions.UserEditAction)と、

URLパスが同じになります。

自動マッピングの主なルールは以下のとおりです。

パッケージのルート:

ルートになるパッケージ名は、struts.xmlで指定するか、struts2や、actions、actionというパッケージ名で始めます。

Actionクラス名のルール:

最後がActionで終わるクラス名にする必要があります。

ActionパッケージとURLの自動マッピングの例:

test.actions.UserEditAction ⇒ /userEdit.action

test.actions.test.HotAction ⇒ /test/hot.action

この自動マッピングの仕組みがあるので、無設定が実現できるのです。

Actionアノテーションは、自動マッピングを利用できない場合に使用します。

または、URLのパスは自動マッピングのとおりで良いが、resultを変えたいなどの場合に使用します。

そういう意味では上記の使い方は、少しおかしいかもしれません。

@Action(”/userEdit”) はURLのパスが"userEdit.action"ということを指定していますが、

自動マッピングでも同じURLパスになります。

しかし、デフォルトのメソッドを指定する方法がなかったので、仕方なく上記のように記述しました。

面倒であれば、デフォルトのexecute()メソッドに処理を記述しても良いと思います。

いずれにしても無設定の場合は、ルールに従っていればstruts.xmlのactionタグを記述しなくて良いので楽になりますが、

ルールに従いたくないときに面倒になるという傾向があります。

<Struts2の設定ファイルのサンプル: src/struts.xml>

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

<!DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"

"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

<!-- これをtrueにするとJSP内のs:submit で、method="hello"のようなメソッド指定ができる -->

<constant name="struts.enable.DynamicMethodInvocation" value="true" />

<!-- WEBの言語設定 -->

<constant name="struts.locale" value="ja"/>

<!-- グローバルなプロパティファイルの指定 -->

<constant name="struts.custom.i18n.resources" value="messages" />

<!-- 【修正点】無設定を有効にする。自動的に検索するようになる。 -->

<constant name="struts.convention.action.disableScanning" value="false"/>

<!-- 【追加点】ここで指定したパッケージ配下を自動検索するようになります。 -->

<constant name="struts.convention.package.locators.basePackage" value="test.actions"/>

<!-- 【追加点】デフォルトで使用するpackage(以下のpackageタグのname属性)を指定します -->

<constant name="struts.convention.default.parent.package" value="struts2test"/>

<!--

URLパスとActionのマッピング。

-->

<package name="struts2test" extends="struts-default">

<!-- デフォルトのコピーからconversionErrorを除外 -->

<interceptors>

<interceptor-stack name="transact" >

<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="multiselect"/>

<interceptor-ref name="staticParams"/>

<interceptor-ref name="actionMappingParams"/>

<interceptor-ref name="params">

<param name="excludeParams">dojo\..*,^struts\..*</param>

</interceptor-ref>

<!--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="transact" />

<!-- 【修正点】 actionタグなくなりました -->

</package>

</struts>

【修正点】

struts.xmlの修正点は、コメントに【修正点】【追加点】のように記述しました。

「無設定(ゼロコンフィギュレーション)」といっても、グローバルなconstantやinterceptorの設定はstruts.xmlで記述します。

もちろん、Actionクラスにアノテーションでローカル設定もできます。

【インターセプターのデフォルト値について】

インターセプターの設定は、設定ファイルの方法と変更していません。

実はActionクラスにアノテーションで設定することもできますが、ここではstruts.xmlのpackageタグに設定したインターセプターを

デフォルトで使用するようにしました。

(constantタグのstruts.convention.default.parent.packageでの設定でデフォルトのpackageタグを設定できます。)

ちなみに基底クラスに記述したアノテーションは継承されるような記述がドキュメントに書かれていました(まだ試していませんが)。

ですので、基底クラスにデフォルト値を記述して、それを継承するという方法でも良いかもしれません。

<各種画面(JSP)のサンプル: WEB-INF/content/userInput.jspなど>

JSPファイルはファイル名だけを変更します。

実は、ファイルのディレクトリのパスとファイル名がActionクラス名と一致するように構成するだけです。

具体的な内容は以下のとおりです。

【ディレクトリとActionクラス名の関係】

・ルートディレクトリ:

WebContent/WEB-INF/content

・ファイル名のルール:

デフォルトは、クラス名から最後の"Action"を取り除いた名前にします。

それ以外は処理結果コードをハイフンで連結した文字列にします。

例:

HotAction (return "success") ⇒ "hot.jsp"

HotAction (return "cert") ⇒ "hot-cert.jsp"

【修正方法】

JSPファイル名の修正内容は以下のようになります。

最後に

無設定の方法を設定ファイルの方法と比較しながら見てきました。

どちらの方法を使用するかは趣味の問題のような気がします。

ちなみに無設定でも設定ファイルの方法でも、妥当性チェックや型変換(conversion)はアノテーションでも記述できますので

それらの設定ファイルもなくすことができます。

しかし、Actionクラスのメソッドにアノテーションがいくつも記述されることになるため、見やすいかどうかは難しい問題です。

かといって設定ファイルで妥当性チェックなどを記述すると、設定ファイルが増えることになります。

【設計のルール】

上記のサンプルで見ましたとおり、設定ファイルの方法で設計したものを、無設定の方法に移行しようとすると

微妙に楽にできません。

例えば、method="doInput"のような設定は2つのやり方の間でうまく合致する方法がありません。

しかし、doInput()メソッドをexecute()という名称にすれば、上記サンプルのように強引なアノテーションをつける必要が

なくなります。これをルール化していれば特に面倒くささが軽減します。

つまり、それぞれの方法に適したルールがあるので、どちらの方法で実装するかを考えて、

その上で適したルールを決めるのが良いと思います。

ここでルールというのは例えば以下のようなものです。

・Actionクラス名のルール(URLに関わるため、SpringSecurityを使用したい場合、特に重要なルールです)

・Actionクラスの継承のルール(アノテーションも継承されるため、デフォルト値を基底クラスに設定するなど)

・メソッド名のルール

・JSPファイル名のルール

・妥当性チェックをアノテーションで行うか、ファイルで行うか

・型変換(conversion)をアノテーションで行うか、ファイルで行うか

・不要になったActionクラスのルール

(無設定の場合は削除するか、クラス名の最後をAction以外にするなどしないと、アクセスできてしまいます)

など

Created Date: 2012/01/21