Struts2.0.9で処理結果を次の画面で使用する
一覧画面に遷移するときなどは、遷移するときにデータを取得し、次に遷移して遷移先JSPで取得したデータを表示・・・という手順を踏むことが多い。
Action内でデータを取得して、次の画面でそのデータを利用する方法をメモ。
一覧画面へ遷移するリンク作成
リンクをクリックしたら一覧画面に遷移する実装とする。
<s:url id=”userListUrl” namespace=”/userlist” action=”userlist”></s:url>
<s:a href=”%{userListUrl}” >一覧画面</s:a>
UserListAction作成
データを取得するアクションを作成する。今回は5件のデータを作成して設定している。
//UserListAction.java
public class UserListAction implements Action {
private List<UserVO> userList;
@Override
public String execute() throws Exception {
AppLogger.debug(“UserListAction.execute”);
//ユーザ一覧を取得(今回はダミーデータを作ってごまかす)
this.userList = new ArrayList<UserVO>();
for(int cnt = 0; cnt < 5; cnt++){
UserVO vo = new UserVO();
vo.setUserName(“userName” + cnt);
vo.setPassword(“password” + cnt);
this.userList.add(vo);
}
return “success”;
}
public List<UserVO> getUserList() {
return userList;
}
public void setUserList(List<UserVO> userList) {
this.userList = [...]
Validatorを動かすと「Could not find action or result」と怒られる
ActionSupportインタフェースを継承したクラスを作って、validation.xmlでValidatorを動かすとこんなのがでた。
2007/09/28 16:51:31 org.apache.struts2.dispatcher.Dispatcher serviceAction
致命的: Could not find action or result
No result defined for action com.daipresents.struts209.action.UserRegAction and result input – action – file:/C:/eclipse/eclipse-jee-europa-win32/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/wtpwebapps/Struts2.0.9/WEB-INF/classes/struts.xml:18:27
どうも、Validationエラーの遷移先であるinputが設定されていないらしい。ActionSupportが実装しているインタフェース、ActionのJavadocをみてみると、
ERROR・・・アクションの実行に失敗 INPUT・・・入力エラーが発生 LOGIN・・・ ログインしてないから実行できない? NONE・・・アクションの実行は成功したけどViewを表示できない SUCCESS・・・アクションの実行に成功
が定義されている。struts.xmlで
<result name=”input”>/error.jsp</result>
とActionに定義したら解決。定数になったんだなー。
Struts2.0.9 BasicValidation
Validationを実装してみる。ユーザの登録画面を作って、「ユーザ名」「パスワード」の入力チェックを作ってみる。
validation.xml
Struts2でもvalidation.xmlを使うけど、使い方がちょっと違う。Actionごとにファイルを用意してあげるので便利になった気がする。
今回はUserRegActionというActionを使うので、validation.xmlの名前は「UserRegAction-validation.xml」という名前になる。これをUserRegAction.javaと同じ場所においてあげる。
<!DOCTYPE validators PUBLIC “-//OpenSymphony Group//XWork Validator 1.0.2//EN”
“http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd”>
<validators>
<field name=”userName”>
<field-validator type=”requiredstring”>
<message>ユーザ名は必須項目です。</message>
</field-validator>
</field>
<field name=”password”>
<field-validator type=”requiredstring”>
<message>パスワードは必須項目です。</message>
</field-validator>
<field-validator type=”stringlength”>
<param name=”minLength”>8</param>
<param name=”maxLength”>32</param>
<param name=”trim”>true</param>
<message>パスワードは${minLength}文字から${maxLength}文字です。</message>
</field-validator>
</field>
</validators>
ユーザ名、パスワードは必須で、パスワードは8文字から32文字までとしている。
UserRegAction.java
ユーザ登録を行うダミーのアクションを作成する。
Struts2.0.9のValidation
Struts2ではXWorkのValidationフレームワークが使える。ValidationhaActionの実行前にValidationルールを入力に行うことができる。
annotationを使ってValidationを行うことも可能。
Struts2 document Validation Annotation
Registering Validators
ValidationルールはValidatorによってハンドルされる。ルールはValidatorFactoryのregisterValidatorメソッドを使って登録されなければならない。
登録よりも簡単な方法として、validators.xmlをクラスパスのルート(/WEB-INF/classes)に置くことで、validatorがこのファイルを変わりに使ってくれる。
下の内容でvalidators.xmlを作れば、フレームワークで定義されている全てのValidatorを宣言できる。
<validators>
<validator name=”required” class=”com.opensymphony.xwork2.validator.validators.RequiredFieldValidator”/>
<validator name=”requiredstring” class=”com.opensymphony.xwork2.validator.validators.RequiredStringValidator”/>
<validator name=”int” class=”com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator”/>
<validator name=”double” class=”com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator”/>
<validator name=”date” class=”com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator”/>
<validator name=”expression” class=”com.opensymphony.xwork2.validator.validators.ExpressionValidator”/>
<validator name=”fieldexpression” class=”com.opensymphony.xwork2.validator.validators.FieldExpressionValidator”/>
<validator name=”email” class=”com.opensymphony.xwork2.validator.validators.EmailValidator”/>
<validator name=”url” class=”com.opensymphony.xwork2.validator.validators.URLValidator”/>
<validator name=”visitor” class=”com.opensymphony.xwork2.validator.validators.VisitorFieldValidator”/>
<validator name=”conversion” class=”com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator”/>
<validator name=”stringlength” class=”com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator”/>
<validator name=”regex” class=”com.opensymphony.xwork2.validator.validators.RegexFieldValidator”/>
</validators>
Note
カスタマイズしたValidatorが必要でないならば、validators.xmlをクラスパスに置くのは必須ではない。
xwork.jarの「com/opensymphony/xwork2/validator/validators/default.xml」に定義されていると、Validatorの所定の設定は自動的に行われる。
警告
カスタムValidatorを定義して、validators.xmlを作成してクラスパスに置いた場合、上記デフォルトのValidatorもvalidators.xmlに定義しないとだめ。
一度validators.xmlがクラスパスに検出されたら、デフォルトのValidator
(com/opensymphony/xwork2/validator/validators/default.xml)はロードされない。ロードされ
るのは、カスタムvalidators.xmlがクラスパスにみつからない場合だけなので注意。
Non-Field Validator Vs Field-Validator
Validatorをvalidation.xmlに定義するには2つ方法がある。
<validator> <field-validator>
Struts2.0.9とTiles2.0.5の使い方
Struts1.3.xでTilesをはじめて使ってみたが、これはかなり使えるプラグインだった。調べてみると、Apache.orgにTilesのサイトがあったので、Struts2のTilesプラグインを使った実装を調べてみる。
まずはインストールからシンプルに使ってみる。
インストール
Tilesをダウンロードしてきて以下の3ファイルを「WEB-INF/lib」に配置する。この場所以外に配置するのは推奨されない。
tiles-api-2.0.5.jar tiles-core-2.0.5.jar tiles-jsp-2.0.5.jar(JSPのサポートがいる場合に入れる)
依存するライブラリを入れる。ダウンロードしたモジュールに入っているのでそれを使えばいい。
Jakarta Commons BeanUtils 1.7.0以上 Jakarta Commons Digester 1.8以上 Jakarta Commons Logging (at least API) 1.1以上
Tilesエンジンの設定
3つの方法がある。
Servletを利用する
web.xmlにTilesのサーブレットを定義。Tilesの定義ファイルを指定してあげる。
<servlet>
<servlet-name>tiles</servlet-name>
<servlet-class>
oorg.apache.tiles.web.startup.TilesServlet
</servlet-class>
<init-param>
<param-name>
org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
</param-name>
<param-value>
/WEB-INF/tiles-defs.xml,/org/apache/tiles/classpath-defs.xml
</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
Listenerを使う
Listenerを使うことも可能。
<listener>
<listener-class>org.apache.tiles.web.startup.TilesListener</listener-class>
</listener>
<context-param>
<param-name>
org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
</param-name>
<param-value>
/WEB-INF/tiles-defs.xml,/org/apache/tiles/classpath-defs.xml
</param-value>
</context-param>
Filterを使う <filter>
<filter-name>Tiles Filter</filter-name>
<filter-class>org.apache.tiles.web.startup.TilesFilter</filter-class>
<init-param>
<param-name>
org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
</param-name>
<param-value>
/WEB-INF/tiles-defs.xml,/org/apache/tiles/classpath-defs.xml
</param-value>
</init-param>
Struts2.0.9のurlタグライブラリ
URLを作成する。URLを作るときにパラメタもつけれるみたい。
使い方
リンクを作ってみる。リンクからActionを呼び出してみる。
<a href=”<s:url action=”userreginit” />”>登録画面</a>
出力は
<a href=”/Struts2.0.9/userreginit.action”>登録画面</a>
みたいなかんじ。本当にURLを作成するだけのタグリブぽい。
名前空間を指定すると以下のようになる。
//index.jsp
<a href=”<s:url action=”userreginit” namespace=”/fujihara” />”>登録画面</a>
//出力
<a href=”/Struts2.0.9/fujihara/userreginit.action”>登録画面</a>
この名前空間の考え方は面白い。
method属性をつけるとメソッド指定で呼ぶことができる。
//index.jsp
<a href=”<s:url action=”userreginit” namespace=”/userreg” method=”init” />”>登録画面</a>
//struts.xml(ここにはmethod属性を書いてない)
<action name=”userreginit”
class=”com.daipresents.struts209.action.UserRegAction”>
<result name=”success”>/WEB-INF/jsp/userreg.jsp</result>
</action
//出力
<a href=”/Struts2.0.9/userreg/userreginit!init.action”>登録画面</a>
でも、これはstruts.xmlに書いたほうが保守性が上がる気がするなー。
Struts2.0.9のiteratorタグ
ループ処理に使えるタグ。シンプルになった気がする。
Listに入ったオブジェクトを表示する
Listの中にUserVOというオブジェクトが入っている場合の表示方法。propertyタグを使ってUserVOのアクセッサを呼び出している。
<table border=”1″>
<tr>
<th>ユーザ名</th>
<th>パスワード</th>
</tr>
<s:iterator value=”userList”>
<tr>
<td><s:property value=”userName” /></td>
<td><s:property value=”password” /></td>
</tr>
</s:iterator>
</table>
2重ループ
UserVO.addressListにはListが入っているとする。userListでループして、その中にあるデータをさらにループさせる場合は以下のようになった。「○○のaddressList」みたいな書き方ではないので違和感を感じる。
<s:iterator value=”userList”>
<tr>
<td><s:property value=”userName” /></td>
<td><s:property value=”password” /></td>
<td>
<s:iterator value=”addressList”>
<s:property /><br />
</s:iterator>
</td>
</tr>
</s:iterator>
ListにStringが入っている場合
propertyタグを使えばString文字列がそのまま表示される。中でtoStringメソッドを読んでいるのかも。
<s:iterator value=”userList”>
<li><s:property /></li>
</s:iterator>
行の背景に色を交互につける
一行ごとに行の背景色を変えたい場合は「IteratorStatus」を作成すればいい。以下の例では「#rowstatus.odd == true」の場合に背景色が変わる。どうもoddは奇数行のときにtrueになるみたい。今回はrowstatusにしているけど、この名前は何でもOKぽい。どんな名前をつけても結局IteratorStatusができるのかも。
<s:iterator value=”userList” status=”rowstatus”>
<s:if test=”#rowstatus.odd == true”>
<div style=”background-color:red”><s:property /></div>
</s:if>
<s:else>
<div><s:property /></div>
</s:else>
</s:iterator> [...]
Struts2.0.9のifタグライブラリ
if判定を行うタグ。
基本的な使い方 <s:if test=”userList != null && !userList.isEmpty()”>
//処理
</s:if>
<s:else>
//処理
</s:else>
//こうも書けるみたい
<s:if test=”%{userList != null && !userList.isEmpty()}”>
//処理
</s:if> オブジェクトを論理式に使う
「#」を使ってオブジェクトを表し、「.」でプロパティにアクセス。
<s:iterator value=”addressList” status=”itStatus”>
<s:property />
<s:if test=”!#itStatus.last”>,</s:if>
</s:iterator>
Struts2.0.9のformタグライブラリ
フォームを作成するタグ。
使い方 <s:form action=”userreg”>
<s:textfield name=”userName” />
<s:submit value=”登録” />
</s:form>
Struts2.0.9のaタグライブラリ
「<a href?」を作るタグ。URLを作成するタグと同時に使うみたい。
使い方 //index.jsp
<s:url id=”userRegInitUrl” namespace=”/userreg” action=”userreginit”></s:url>
<s:a href=”%{userRegInitUrl}” >登録画面</s:a>
//出力
<a href=”/Struts2.0.9/userreg/userreginit.action”>登録画面</a>
Struts2.0.9のタグライブラリ
Struts2タグで利用できるタグを紹介。これを使えばFormの値の受け渡しができるはず。
宣言はこんな感じらしい。
<%@taglib prefix=”s” uri=”/struts-tags” %>
Struts2.0.9でSessionにアクセスする
ユーザのセッションにActionからアクセスしたいときはこのインタフェースを実装しなければならない。
このインタフェースはサーブレット環境の場合にのみ利用できる。
このインタフェースを使ってサーブレット環境に関係するActionを作ると、ユニットテストが難しくなるので避けるべき。
ユーザ登録画面に確認画面を作る
ユーザの登録画面で入力して登録ボタンを押すと確認画面が表示され、その後、登録ボタンを押すと登録処理が実行されるという画面遷移に変更する。
登録画面のJSP
actionがuserconfirmに変わっただけ。
<s:form action=”userconfirm” method=”post”>
<s:textfield label=”userName” name=”userName” />
<s:password label=”password” name=”password” />
<s:submit value=”登録” />
</s:form> 確認画面へのAction
UserRegActionでSessionAwareをimplementsしてセッションMapを用意する。
private Map sessionMap;
public void setSession(Map session) {
this.sessionMap = session;
}
さらに、confirmメソッドを追加。ここでは入力されたデータをセッションに移し変えている。
public String confirm() throws Exception {
AppLogger.debug(“confirm画面へ”);
this.sessionMap.put(“USERNAME”, this.userName);
this.sessionMap.put(“PASSWORD”, this.password);
return SUCCESS;
} 確認画面のJSP
セッションに入ったデータを表示するだけ。
<s:property value=”#session.USERNAME”/><br />
<s:property value=”#session.PASSWORD”/>
<s:form action=”userreg” method=”post”>
<s:submit value=”登録” />
</s:form> 登録Action
登録処理は変わらず。入力値はセッションの値を使う。@SkipValidationを指定しないと、Validatorが走ってしまうので注意。
@SkipValidation
public String execute() throws Exception {
//パラメタからVOを作成する
UserVO userVO = [...]
Struts2.0.9 Interceptorsの実装
インターセプタを作るためには「com.opensymphony.xwork2.interceptor.Interceptor」を実装しなければならない。
Interceptorインタフェース
以下の3メソッドが定義されている。
void destroy() void init() String intercept(ActionInvocation invocation) initメソッド インターセプターがインスタンス化された後に呼び出される。インターセプターの初期化に使える。 interceptメソッド ここにインターセプタの処理を実装する。メソッドは、Strutsで使う他のWebリソースへリクエストをforwardする結果を返す。 destroyメソッド アプリケーション停止時にリソースのリリースを行う。
インターセプタはスレッドセーフでなければならない。
AbstractInterceptor
AbstractInterceptorはinitメソッドとdestroyメソッドの空の実装を提供する。これをつかえば2メソッドを実装しなくてもよくなる。
開始/終了ログ出力インターセプタを作ってみる
Actionの開始、終了時にログを出力するインターセプタを作成する。LoggingInterceptorがあるけど、自分で用意したほうがカスタマイズが楽そう。
インターセプタクラスの作成
AbstractInterceptorを継承して作成した。Action終了時にも呼び出したいので、PreResultListenerをaddしている。これをしないと終了時に動いてくれない。
//AbstractInterceptor.java
public class ActionLoggingInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println(“[開始]” + invocation.getAction().getClass().getSimpleName());
//後処理用
invocation.addPreResultListener(new PreResultListener() {
public void beforeResult(ActionInvocation invocation, String result) {
System.out.println(“[終了][" + result + "]” + invocation.getAction().getClass().getSimpleName());
}
});
return invocation.invoke();
}
} struts.xmlの修正
actionLoggingStackを定義してその中で上記クラスを呼び出す設定を行う。たいていの場合、defaultStackを最後に呼び出す。呼び出さないとvaliadtorなどが動いてくれない。
//struts.xml
<interceptors>
<interceptor name=”actionlogging” class=”com.daipresents.struts209.interceptor.ActionLoggingInterceptor”/>
<interceptor-stack name=”actionLoggingStack”>
<interceptor-ref name=”actionlogging”/>
<interceptor-ref name=”defaultStack” />
[...]
Struts2.0.9 ExceptionInterceptor
Exception
Interceptorは、例外ハンドリングの中心機能を形成している。例外ハンドリングは例外を結果コードにマッピングすることができる。これは、
Actionが予期せぬ例外を投げる変わりに結果コードを投げているように扱うことができる。例外が発生したとき、例外をExceptionHolderでラップして、簡単に例外を扱えるようになっている。
引数 logEnabled 任意。ログの有効無効(true or false) logLevel 任意。ログレベル。デフォルトでDebug。(trace, debug, info, warn, error, fatal) logCategory 任意。カテゴリを指定する場合に必要。デフォルトで「com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor」になる。 設定方法
struts.xmlに以下の設定を記述
<global-results>
<result name=”system_error”>/error.jsp</result>
<result name=”runtime_error”>/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping exception=”java.lang.RuntimeException” result=”runtime_error”/>
</global-exception-mappings>
<action name=”userreg”
class=”com.daipresents.struts209.action.UserRegAction”>
<exception-mapping exception=”java.lang.Exception” result=”other_error”/>
<result name=”success”>/WEB-INF/jsp/complete.jsp</result>
<result name=”input”>/WEB-INF/jsp/userreg.jsp</result>
<result name=”error”>/WEB-INF/jsp/userreg.jsp</result>
</action>
RuntimeExceptionの場合や、システムとしてエラーの場合はerror.jspに遷移するようにしている。
error.jspには例外情報を出力させてみる。
//error.jsp
<P><s:property value=”exception.message” /></P>
<P><s:property value=”exceptionStack” /></P>
これで、Action内で例外が発生するとerror.jspに遷移してくれる。例外のハンドリングをActionに書かなくてもいいのがよい感じ。
Interceptorの拡張
例外を公開するためにカスタムハンドラを追加したい場合、publishExceptionメソッドをオーバーライドすることができる。デフォルトの実装では、スタックにExceptionHolderをプッシュする実装になっている。そこにlog処理などを追加することができる。
ExceptionMappingInterceptorの拡張
ExceptionMappingInterceptor Javadoc
うまくうごいてくんない。Documentみてもかいてないしなー。
僕について
Dai Fujihara
A hero can be anyone.
藤原大はマネージャでありアジャイル実践者だ。そして、プロジェクトリーダー、チェンジ・エージェント、アジャイルコーチ、トレーナーでもある。彼はまたRedmine、Jenkinsといった開発を支援するツール環境の整備や、アジャイル開発を活用した創造的なソフトウェア開発の支援を行っている。さらに、趣味は沖縄離島巡りらしい。
ここ最近の人気
開発ツールを使うと「思いやり」が減る(前半) #swat… 1,028 view(s)
アジャイルコミュニティは超めんどうくさい… 502 view(s)
開発ツールを使うと「思いやり」が減る(後半) #swat… 495 view(s)
3年使ったRedmineの使い方について共有したい10の… 370 view(s)
チームとタワーを創造せよ!マシュマロチャレンジでチームビ… 277 view(s)
Javaで入力チェックに使える正規表現まとめ… 121 view(s)
Redmineプラグイン開発 – 史上最高のチームプラグ… 95 view(s)
LinkStationのようなNASを買ってもバックアッ… 73 view(s)
DAOとかDTOとかVOとかEntityとか… 68 view(s)
HYの「AM11:00」は本当に彼女が亡くなった時の曲な… 60 view(s)
永久保存の本
Jonathan Rasmusson (著), 西村 直人 (翻訳), 角谷 信太郎 (翻訳)
アジャイルサムライ―それはソフトウェアを顧客に届ける猛々しきプロフェッショナルだ。本書では、圧倒的なアジャイルプロジェクトの姿を見せる。2011年爆発的にヒットしたアジャイル開発に情熱を持つエンジニアに届けたい本。
Mike Cohn (著), マイク コーン (著), 安井 力 (翻訳), 角谷 信太郎 (翻訳)
採用した現在のタイトルは、見積りや計画づくりといったプロセスを、アジャイルに進めなければならないと謳っているのだ。見積りと計画づくりがアジャイルでないのに、プロジェクトがアジャイルであるということはありえない。(イントロダクションより)
Venkat Subramaniam (著), Andy Hunt (著), 木下 史彦 (監訳), 角谷 信太郎 (監訳)
アジャイルな習慣とは一体何なのか?本書ではプラクティスを交えながら、その姿勢を読者に問いかけている。世代や役割をこえて色褪せない「アジャイル」に対する良書。Amazonレビュー
メアリー・ポッペンディーク (著), トム・ポッペンディーク (著), 高嶋 優子 (翻訳), 天野 勝 (翻訳), 平鍋 健児 (翻訳)
「トヨタ生産方式」を源流にする「リーン開発」をソフトウエア開発に取り入れるための具体的方法を紹介した本です。本書は、リーンの7大原則を「価値」「ムダ」「スピード」「人」「知識」「品質」「パートナー」に整理し、ソフト開発現場にどうしたら効果的に適用できるかを、多くの実例を交えながら具体的に説明します。
タグ
Agile ant Apache bash Eclipse GlassFish install Java Javascript kobo Linux log4j Management Maven Open Source PHP Pukiwiki Python Redmine Ruby Ruby on Rails Scrum Spring Struts Struts2 Subversion Test Tomcat Trac VBA Web WebDriver WebLogic Windows WordPress 働く 勉強会 嫁(ベータ) 思い出し笑う 我思う 旅する 映画/ドラマ 英語を話す 読むと聞く 過去を語るアーカイブ









