- 追加された行はこの色です。
- 削除された行はこの色です。
* Struts2 メモ [#rcce0881]
Struts2は[[Struts:http://struts.apache.org/]]というよりは[[WebWork2:http://www.opensymphony.com/webwork/]]の動作を多く継承している印象。
- [[Struts2:http://struts.apache.org/2.x/]]
- [[Velocity:http://www.jajakarta.org/velocity/]]
- [[Spring:http://www.springframework.org/]]
- [[Apache Tomcat:http://tomcat.apache.org/]]
- [[WebWork:http://www.opensymphony.com/webwork/]]
** 設定 [#o5ead497]
とりあえず、インスコとかEclipseとかの設定は割愛(気が向いたらメモるけど)。
Struts2を利用するというとき、Struts経験者は、まずその過去の経験を一度忘れる。WebWork経験者は結構そのままの知識で移行可能。
Struts2の設定の基本は次のファイル。
+ struts.properties
+ web.xml
+ struts.xml
+ struts-default.xml
+ struts-plugin.xml
開発時に頻繁に書き換えるのは3になるでしょう。
*** struts.xml [#md35108c]
#code("HTML"){{
<?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="true" />
<include file="category1.xml"/>
<include file="category2.xml"/>
<include file="category3.xml"/>
<!-- Add packages here -->
</struts>
}}
アクションやインターセプタなどの定義はこのファイルに書くことになるが、規模が大きくなるに連れてこのファイルに書く設定の量が肥大化してくる。そこで、あるカテゴリごと、機能ごとなどにxmlを分割して作成し、それをここにincludeすることができる。
例えば上記ではcategory1.xml、category2.xml、category3.xmlの3つの外部ファイルをincludeしている。
category1.xml の例
#code("HTML"){{
<?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="category1" namespace="/category1" extends="struts-default">
<action name="HelloWorld" class="category1.HelloWorld">
<result>/category1/HelloWorld.vm</result>
</action>
<action name="login" class="category1.LoginAction">
<result name="input">/category1/login.vm</result>
<result name="success">/category1/top.vm</result>
</action>
<!-- Add actions here -->
</package>
</struts>
}}
*** ワイルドカードマッピング [#z0ef821d]
アクションが呼び出されるときの挙動例。
次のように書いたら、
<action name="login" method="login" class="category1.LoginAction">
<result name="input">/category1/login.vm</result>
<result name="success">/category1/top.vm</result>
</action>
+ LoginActionクラスのloginというメソッドが呼び出される。
+ メソッドが失敗するとinputという文字列が返り、その場合はLogin.vmで示されるページが表示される。
+ メソッドが成功するとsuccessという文字列が返り、Top.vmで示されるページが表示される。
Struts2ではexecute()というメソッドを必ず用意しなければならない、ということはない。好きな名前のメソッド名をつくって使える。
ちなみに、vmというのはvelocityというテンプレートエンジンが使用するファイルの拡張子。jspのようなもの。
上記は、nameで指定されているアクション(エイリアス)名とメソッド名が同じなので、次のようにも記述できる。
<action name="*" method="login" class="category1.LoginAction">
<result name="input">/category1/login.vm</result>
<result name="success">/category1/top.vm</result>
</action>
これでlogin.doなどで呼び出されたら、LoginActionクラスのloginメソッドが呼び出されることになる。
<action name="*Menu" method="{1}" class="category1.MenuAction">
<result name="input">/category1/init.vm</result>
<result name="success">/category1/menu.vm</result>
</action>
この場合、呼び出されるメソッド名は自動的にMenuActionクラスが実装しているメソッドから検索される。例えば、initMenu.doなどと呼び出せば、methodには"init"が挿入され、MenuActionのinitメソッドが呼び出されることになる。
さらに上記はresultで指定されているinit.vmというファイル名がメソッド名と同じなので、
<action name="*Menu" method="{1}" class="category1.MenuAction">
<result name="input">/category1/{1}.vm</result>
<result name="success">/category1/menu.vm</result>
</action>
と書けば、戻り値がinputのときにinit.vmというページが表示されることになる。
** アクションの拡張子 [#d519abc9]
Struts2では、標準で"action"という拡張子が設定されている(Strutsの"do"に相当する拡張子)。これが気に入らないという場合、これも自由に変更可能。
struts.properties ファイルの中に
#code{{
### Used by the DefaultActionMapper
### You may provide a comma separated list, e.g. struts.action.extension=action,jnlp,do
struts.action.extension=action
}}
という行があるので、ここを好きな拡張子に書き換えるか追記する。
例えば、従来のStrutsのようにdoじゃないとダメだという人は、
struts.action.extension=do
と書いてしまえば良い。
ここは何でも良い。極端な話、"html"とか"aspx"などを指定することもできるので、静的ページや.NETで動いているページに偽装することもできるヨ?(そんな意味ないけど)。
- [[struts.properties:http://struts.apache.org/2.x/docs/strutsproperties.html]]
** 基本的なアクション [#a17c5afd]
Strutsのexecute()メソッドではActionMapping、ActionForm、HttpServletRequest、HttpServletResponseの4つの引数が渡されてきていた。しかし、Struts2のアクションクラスで呼び出されるメソッドには引数がない。Strutsから移行してきた人の多くは、まずこれに戸惑うはず?
どこからパラメータを取れば良いのか?の回答は、どこでも取れる、ということになる。
例えば、ログイン画面から入力されたユーザ名とパスワードをアクションが取得して認証する、という処理を書きたい場合、
#code("java"){{
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private static final long serialVersionUID = 1L;
/**
* ログイン処理を実行する。
*/
public String login() throws Exception {
// NOTICE authentication() はどこかに作成しておく。
if (authentication(userName,password)) {
return "success";
}
return "input";
}
/**
* ユーザ名
*/
private String userName;
/**
* ユーザ名を設定する。
*/
public void setUserName(String userName){
this.userName = userName;
}
/**
* パスワード
*/
private String password;
/**
* パスワードを設定する。
*/
public void setPassword(String password){
this.password = password;
}
}
}}
と書けば良い。
ActionSupportを継承したクラスをアクションクラスとし、パラメータ名を設定するsetterメソッド(publicスコープで)を用意しておくだけ。
これで、アクションが起動されたときに、その名前のパラメータが渡されてきたら、自動的にそのsetterが呼び出され、メンバ変数に設定されることになる。なんと便利。
** モデルドリブン [#s3fe2005]
アクションの中にすべての変数を用意してそこにsetterを書いても良いが、パラメータは別オブジェクトに分離して持たせることができる。そのオブジェクトのことを「モデル」と呼ぶ。
モデルとなるクラスにはパラメータとなる変数を持たせておいて、そのsetter、getterを用意しておくだけ。これで、アクションクラスに持つパラメータはモデルのみとなり、処理に専念するクラスにすることができる。
モデルドリブンを実装するには、ModelDrivenをimplementsしておく。
モデルドリブンを使用するには、struts.xmlにModelDrivenInterceptorを設定し(多分デフォルトで設定されている?)、アクションクラスではModelDrivenをimplements、getModel()メソッドを実装しておく。
アクション側
#code("java"){{
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork.ModelDriven;
import com.opensymphony.xwork2.ModelDriven;
import category1.LoginModel;
public class LoginAction extends ActionSupport implements ModelDriven {
private static final long serialVersionUID = 1L;
/**
* ログイン処理を実行する。
*/
public String login() throws Exception {
// NOTICE authentication() はどこかに作成しておく。
if (authentication(loginModel.getUserName(),loginModel.getPassword())) {
return "success";
}
return "input";
}
/**
* パラメータを保持するモデル
*/
private LoginModel loginModel = new LoginModel();
/**
* モデルを取得する。
*/
public Object getModel() {
return loginModel;
}
}
}}
モデル側
#code("java") {{
#code("java"){{
public class LoginModel {
private String userName;
public void setUserName(String userName){
this.userName = userName;
}
public String getUserName(){
return userName;
}
private String password;
public void setPassword(String password){
this.password = password;
}
public String getPassword(){
return password;
}
}
}}
** Strutsのアクションの引数を取得したい [#p610e7b1]
それでもやっぱりStruts時代に取得できていたHttpServletRequestなどの情報もほしいよ?という場合もある。それらの情報は消えているわけじゃなく、ちゃんとどこかに保持されているので、それを取り出せるようなsetter、getterを実装すれば良い。
例えばHttpServletRequestを取得する場合、ServletRequestAwareインタフェースをimplementsしてsetServletRequest()を実装する。
#code("java"){{
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import org.apache.struts2.interceptor.ServletRequestAware;
public class ExampleAction extends ActionSupport
implements ModelDriven, ServletRequestAware {
private HttpServletRequest request;
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
}}
- [[org.apache.struts2.interceptor:http://struts.apache.org/2.0.6/struts2-core/apidocs/org/apache/struts2/interceptor/package-summary.html]]
- [[Struts2への移行:http://www.infoq.com/jp/articles/migrating-struts-2-part2]]
** インターセプタ [#o9d3426a]
** 参考サイト [#kaee5308]
- [[「夜を告げるモノ。」:http://www.gigafield.org/projects/trac]]
-- [[Struts2入門:http://www.gigafield.org/projects/trac/wiki/Struts2]]
- [[Struts2サンプル集:http://nullpo.2log.net/home/struts2/]]
- [[WebWork2 + Velocity:http://ww36.tiki.ne.jp/~supergibby/webwork2/]]
- [[Struts2を使ってみる:http://www15.plala.or.jp/k_maeba/struts2/]]
** 公式 [#f323e2d0]
- [[Apache:http://www.apache.org/]]
-- [[Jakarta Project:http://jakarta.apache.org/]]
-- [[Struts:http://struts.apache.org/]]
- [[OpenSymphony:http://www.opensymphony.com/]]
- [[Java Developer Connection:http://sdc.sun.co.jp/java/]]
-- [[Java2 SDK ドキュメント:http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/index.html]]
-----
[[MLEXP. Wiki]]