Struts2のblank.warを読んでみた
Struts2がデファクトになるのかなぁ。どうだろう。わかんないけどかなり知っておいて損はないだろう。ということでStruts2の勉強開始。struts-2.0.9を対象に。
アクション
Struts2でのアクションクラスはActionSupportクラスを継承するようだ。
サンプルには以下のクラスが定義されている。
- ExampleSupportクラス ... サンプル用のベースクラス
- HelloWorldクラス ... メッセージを表示するアクションクラス
- Loginクラス ... Login処理っぽいことを行うアクションクラス
ExampleSupportクラスはActionSupportクラスを継承しているだけで中身は空っぽ。
ActionSupportクラスはActionクラスをサポートしてくれるもの(そのままやな)。"success"をリターンするexecute()メソッドや、"input"をリターンするinput()メソッドなどを提供する。http://struts.apache.org/2.0.9/struts2-core/apidocs/com/opensymphony/xwork2/ActionSupport.html#input()
HelloWorldクラス
アクションを定義している部分はこれ。
package example; /** * <code>Set welcome message.</code> */ public class HelloWorld extends ExampleSupport { public String execute() throws Exception { setMessage(getText(MESSAGE)); return SUCCESS; } ...
execute()メソッドがアクションとして実行されるメソッド。Stringをリターンすればいいみたい。シンプル!!!ここでは、"success"という文字列をリターンしている。
getText(arg)というメソッドは、ActionSupportクラスが提供するもので、メッセージリソースからメッセージを取得するもの。
jsp
struts2のタグリブはこんな感じで定義する。
<%@ taglib prefix="s" uri="/struts-tags" %>
HelloWorld.jsp
HelloWorld.jspからStruts2のタグライブラリの使い方を見てみる。
<title><s:text name="HelloWorld.message"/></title>
リソースファイルからnameで指定したキーに対応するプロパティに置き換えるタグ。
Generic TagsのData Tagsという種類。
<h2><s:property value="message"/></h2>
スタックからmessegeというプロパティの値に置き換えるタグ。おそらくスタック上にHello
Worldオブジェクトが乗っかっていれば、HelloWorldオブジェクトに対してgetMessage()が呼ばれているんだと思われる。
こいつも、Generic TagsのData Tagsという種類。
<s:url id="url" action="HelloWorld"> <s:param name="request_locale">en</s:param> </s:url> <s:a href="%{url}">English</s:a>
こいつらも、Generic TagsのData Tagsという種類。
設定ファイル
web.xml
一部抜粋するとこんな感じ。
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
FilterDispatcherなるFilterがActionを実行する。すべてのリクエストをマッピングしないといけないようだ。http://struts.apache.org/2.0.9/struts2-core/apidocs/org/apache/struts2/dispatcher/FilterDispatcher.html
struts.xml
Struts1のときはstruts-config.xmlだったのだがstruts.xmlになった。あと、この設定ファイルの置き場所が、クラスパス上になった。サンプルでは、classes直下においてある。
<?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> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="false" /> <include file="example.xml"/> <!-- Add packages here --> </struts>
struts-core-2.0.9.jarにorg/apache/struts2/default.propertiesなるファイルがあり、様々なプロパティのデフォルト値が定義してある。struts.devModeについてはこんな感じ。
### when set to true, Struts will act much more friendly for developers. This
### includes:
### - struts.i18n.reload = true
### - struts.configuration.xml.reload = true
### - raising various debug or ignorable problems to errors
### For example: normally a request to foo.action?someUnknownField=true should
### be ignored (given that any value can come from the web and it
### should not be trusted). However, during development, it may be
### useful to know when these errors are happening and be told of
### them right away.
struts.devMode = false
ふーん。
で最後に、
example.xml
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> <package name="example" namespace="/example" extends="struts-default"> <action name="HelloWorld" class="example.HelloWorld"> <result>/example/HelloWorld.jsp</result> </action> <action name="Login_*" method="{1}" class="example.Login"> <result name="input">/example/Login.jsp</result> <result type="redirect-action">Menu</result> </action> <action name="*" class="example.ExampleSupport"> <result>/example/{1}.jsp</result> </action> <!-- Add actions here --> </package> </struts>
この定義の意味するところはこういうこと。
- /example/HelloWorld.actionというリクエストに対してexample.HelloWorldクラスを対応付けている。execute()メソッドを実行した後に、/example/HelloWorld.jspに遷移する。
- /example/Login_メソッドというリクエストに対してexample.Loginクラスのメソッドを対応付けている。呼び出したメソッドがinputという文字列を返した場合は、/example/Login.jspに遷移する。inputという文字列でない場合は、/example/Menu.actionにリダイレクトする。
- /example/JSPファイル名.actionというリクエストに対してexample.ExampleSupportクラスを対応付けている。execute()メソッドを実行後、/example/JSPファイル名.jspに遷移する。
あと、この定義には明示されていないが、/example/Login.actionというリクエストに対して、example.Login#execute()が対応付けられている。#デフォルトのルールだろうか?
そのほかのファイル
Login-validation.xmlなるファイルを定義することで、Loginアクションのバリデーションを定義できるっぽい。
<validators> <field name="username"> <field-validator type="requiredstring"> <message key="requiredstring"/> </field-validator> </field> <field name="password"> <field-validator type="requiredstring"> <message key="requiredstring"/> </field-validator> </field> </validators>
どこにもこのファイルを参照する定義は書いてないなぁ。アクションクラス名-validation.xmlとして、クラスパス上に配置するってことがルールなのかな。
定義ファイルは参照しやすくなっているみたいだけど、実際にバリデーション定義がやりやすいんだろうか?Struts1のバリデータプラグインとかではメンテがつらかったからなぁ。#テストのことを考えて、結局、ActionFormに書くことが多かった気がする。
ふぅ。