Strutsには、エラーメッセージをJSPで表示する機能が備わっている。
Actionクラス内で明示的にエラーをセットして画面遷移させる方法と、発生した例外を処理する方法がある。
普通に画面(JSP)にエラーメッセージを出力する場合の処理の流れは、
となる。
生成する際、メッセージ自体はプロパティーファイル(メッセージリソースファイル)に書いておき、プログラムからはそのキーを指定することになる。
html:errors(ErrorsTagクラス)がキーから文言に変換する。
Strutsのサンプルによると、メッセージの文言を書いておくファイルはMessageResources.propertiesらしい。
中身は普通のプロパティーファイルと同様の書き方。
#comment errors.msg.key1=HogeHoge errors.msg.key2=zzz {0},{1}
このファイルの名前および場所はstruts-config.xmlで指定する。
<struts-config> 〜 <message-resources parameter="MessageResources" /> </struts-config>
message-resources要素のparameter属性に、ファイル名の拡張子を除いた部分を書く。
「MessageResources」と指定した場合、実行環境が日本であれば、
MessageResources_ja_JP.properties
MessageResources_ja.properties
MessageResources.properties
のうち、存在している上位のファイルが使われる。(たぶん、ResourceBundleの仕組みが使われている)
実際にこれらのファイルを置く場所は、コンパイルされたclassファイルと同じ場所。
Eclipseの場合、src(javaソースファイルの置き場所)と同じところに置けば、自動的にclassファイルの場所にコピーしてくれる。
上記の例だと、パッケージ(ディレクトリー)を何も指定していないので、デフォルトパッケージ扱い、すなわちsrcの直下にファイルを置くことになる。
src/jp/hishidama/message/MessageResources.propertiesを使いたいなら、
「<message-resources parameter="jp/hishidama/message/MessageResources" />
」あるいは
「<message-resources parameter="jp.hishidama.message.MessageResources" />
」となる。
Action#execute()の中でエラーをセットする方法。
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionErrors; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages;
public class Sample4Action extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
ActionErrors errors = new ActionErrors();
ActionMessage msg = new ActionMessage("errors.msg.key1");
errors.add(ActionErrors.GLOBAL_MESSAGE, msg);
addErrors(request, errors); //親クラスのメソッドを呼び出す
return mapping.findForward("failure");
}
}
Actionクラス内に、addErros()という、エラーメッセージを保持するメソッドがあるので、これを呼び出す。
この引数はActionErrorsクラスであり、複数のエラーメッセージを保持できる。
なので、名前を付けてadd()する。代表的なエラーを保持する場合は、GLOBAL_MESSAGEという名前を使うらしい。
(ActionErrorsはActionMessagesのサブクラスであり、GLOBAL_MESSAGEもActionMessagesで定義されている)
ActionMessageのコンストラクターの第1引数にはメッセージキーを指定する。
実際の文言は、JSPに出力される際にメッセージリソースファイルから取得される。
その文言の中に可変項目({0}や{1}など)がある場合、ActionMessageのコンストラクターの第2引数以降でその値を指定する。
可変項目が2つあったとすると、以下のようになる。
ActionMessage msg = new ActionMessage("errors.msg.key2", "可変値0", "可変値1"); あるいは ActionMessage msg = new ActionMessage("errors.msg.key2", new Object[]{ "可変値0", "可変値1" });
Action#addErrors()の中でやっていることは、主にリクエストアトリビュートにActionErrorsを保持すること。
(既に保持していた場合は、そこに追加する)
保持する際のキー名はGlobals.ERROR_KEY(値は"org.apache.struts.action.ERROR"
)が使われる。
JSPファイルでは、html:errorsタグを使ってエラーメッセージを表示する。
<%@ page contentType="text/html; charset=Windows-31J"%> <%@taglib uri="/struts-html" prefix="html"%> <html:html> <head> <title>error sample</title> </head> <body> <h1>エラーサンプル</h1> <h2>Strutsのhtml:errors</h2> <p><html:errors /></p> </body> </html:html>
html:errorsに属性を何も指定しない場合、Actionで登録した複数のエラーメッセージが全て表示される。
エラーが何も登録されていない場合は、何も表示されない。
property属性にActionErrorsでメッセージを追加した際の名前を指定すると、そのメッセージだけが表示される。
<p><html:errors property="org.apache.struts.action.GLOBAL_MESSAGE" /></p>
name属性を指定すると、リクエストアトリビュートからその名前で登録されたActionErrors(厳密にはActionMessages)が使われる。
省略時はGlobals.ERROR_KEYが使われる。(すなわち、addErrors()のデフォルト状態)
Actionクラスでのエラーメッセージの生成 | JSPでの出力方法 | 出力例 | 備考 |
---|---|---|---|
errors .add(ActionErrors.GLOBAL_MESSAGE, msg0); |
<html:errors /> |
共通エラー |
|
errors .add("err1", msg1); |
<html:errors /> |
エラー1 |
|
<html:errors property="err1"/> |
エラー1 |
プロパティー属性指定時 | |
errors .add(ActionErrors.GLOBAL_MESSAGE, msg0); |
<html:errors /> |
共通エラーエラー1 |
メッセージの文言に改行「<br>」等が含まれていない場合、 複数のメッセージがくっついて出てしまう。 |
<html:errors property="err1"/> |
エラー1 |
||
同上 | <html:errors |
<p><font color="red"> |
メッセージリソースファイルにヘッダー・フッター類を指定した例head.key=<p><font color="red"> |
同上 | <html:errors /> |
<p><font color="red"> |
ヘッダー・フッター類にはデフォルトのキーがあるので メッセージリソースファイルにそれを設定しておけば JSP上のerrorsタグの属性は省略可能 errors.header=<p><font color="red"> |
errors .add(ActionErrors.GLOBAL_MESSAGE, msg2); |
<html:errors name="MYERR" /> |
共通エラー2 |
name属性指定時 |
Action#excute()の中で例外が発生した際に、その例外をキャッチすることが出来る。
struts-config.xmlのアクションマッピング(action-mappingsのaction要素)内に記述した場合はそのアクションのみ、
全アクション共通でキャッチしたい場合はglobal-exceptionsを記述する。
アクション固有の例外捕捉を行いたい場合、action-mappingsの該当action要素内にexception要素を記述する。
<action-mappings>
〜
<action path="/sample4submit" type="jp.hishidama.sample.struts.sample4.Sample4Action" name="sample4Form" scope="request">
<exception type="jp.hishidama.sample.struts.sample4.Sample4Exception"
path="/error.jsp"
key="msg.key.exception" />
<forward name="success" path="/index.jsp" />
<forward name="failure" path="/error.jsp" />
</action>
</action-mappings>
exception要素のtype属性に、キャッチしたい例外クラス名を書く。
その例外の全ての種類のサブクラスが捕捉対象になる。
(別途サブクラスをtype属性に記述したexception要素があれば、そちらが優先される。struts-config.xml内の記述順序は無関係)
path属性は、その例外をキャッチした際に遷移する画面(パス・URI)を指定する。
JSPファイルだけでなく、他のアクションへ遷移(フォワード)することも出来る。
省略した場合は、action要素のinput属性のパスに遷移するらしい。
key属性は、エラーメッセージの文言を表すキー。(DTDを見ると必須項目ではないのだが、必須っぽい)
メッセージリソースファイルからそのキーで文言が取得される。
このキーでActionErrorsが作られてリクエストにGlobals.ERROR_KEYで保持されるので、遷移先のエラー画面
ではhtml:errorsを使ってその文言を表示できる。
(例外を発生させた箇所に応じてメッセージを指定したい場合は、ModuleExceptionを使う。)
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
throw new Sample4Exception();
}
msg.key.exception=struts-config.xmlで指定されたメッセージ
例外をキャッチして遷移した先のJSPのhtml:errorsタグでは、exception要素のkey属性で指定されたメッセージを表示できる。
ただしこれでは、例外発生箇所ごとに別の文言を指定することが出来ない。(struts-config.xml上で固定のキーだから)
ModuleExceptionという例外を使えば、例外発生箇所でエラーメッセージを指定することが出来る。
import org.apache.struts.util.ModuleException;
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
throw new ModuleException("msg.key.module-exception");
// throw new ModuleException("msg.key.module-exception2", "引数0", "引数1");
// throw new ModuleException("msg.key.module-exception2", new Object[]{ "引数0", "引数1" });
//コンストラクターの引数の種類は、ActionMessageと同じ
}
msg.key.exception=struts-config.xmlで指定されたメッセージ msg.key.module-exception =明示的に指定したメッセージ msg.key.module-exception2=明示的に指定したメッセージ{0}{1}
<exception type="org.apache.struts.util.ModuleException"
path="/error.jsp"
key="msg.key.exception" />
例外をキャッチした際に、独自の処理を行うことも出来る。
struts-config.xmlのexception要素にhandler属性を指定する。
<action-mappings>
〜
<action path="/sample4submit" type="jp.hishidama.sample.struts.sample4.Sample4Action" name="sample4Form" scope="request">
<exception type="jp.hishidama.sample.struts.sample4.Sample4Exception"
path="/error.jsp"
key="msg.key.exception"
handler="jp.hishidama.sample.struts.sample4.Sample4ExceptionHandler" />
<forward name="success" path="/index.jsp" />
<forward name="failure" path="/error.jsp" />
</action>
</action-mappings>
package jp.hishidama.sample.struts.sample4;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ExceptionHandler;
import org.apache.struts.config.ExceptionConfig;
public class Sample4ExceptionHandler extends ExceptionHandler {
@Override
public ActionForward execute(Exception ex, ExceptionConfig ae,
ActionMapping mapping, ActionForm formInstance,
HttpServletRequest request, HttpServletResponse response) throws ServletException {
System.out.println(ex.getClass());
//メッセージ生成
ActionMessage msg = new ActionMessage("msg.key.handler");
String property = Globals.ERROR_KEY;
ActionForward forward = new ActionForward(ae.getPath());
String scope = "request";
//リクエストにエラーメッセージを保存
storeException(request, property, msg, forward, scope);
if (!response.isCommitted()) {
return forward;
}
return null;
}
}
例外ハンドラーは、ExceptionHandlerを継承し、execute()をオーバーライドする。
第1引数は捕捉した例外。
第3引数のmappingは(Action#execute()のmappingと同様に)struts-config.xmlのaction要素の内容を保持している。
同様に、第2引数のExceptionConfigはexception要素の内容を保持している。
例外ハンドラーの中でActionMessageを生成してリクエストに詰めてやれば、遷移先からhtml:errorsでメッセージを表示することが出来る。
これにはstoreException()というメソッドが使える。(ActionのaddErrors()と似たようなもの)
あるいは、遷移先(forward)もここで変更することが出来る。
struts-config.xmlのexception要素でhandler属性を省略した場合、ExceptionHandlerクラスそのものが使われるようだ。
ModuleExceptionに指定したメッセージ情報からActionMessageやActionErrorsを作り出してリクエストにセットするのは、ここで行われている。
struts-config.xmlの個別のaction要素に捕捉する例外を書くのではなく、全てのアクションからの例外を共通にキャッチしたい場合は、global-exceptionsを使う。
<struts-config> <form-beans> 〜 </form-beans> <global-exceptions> <exception type="jp.hishidama.sample.struts.sample4.Global4Exception" path="/error.jsp" key="msg.key.exception" handler="jp.hishidama.sample.struts.sample4.Sample4ExceptionHandler" /> </global-exceptions> <action-mappings> 〜 </action-mappings> </struts-config>
global-exceptionsの中にexcpetion要素を書く。書く内容はaction要素内に書く場合と同じ。
web.xmlにはerror-pageという要素があって、そこでも例外をキャッチして処理することが出来る。
global-exceptionsはそのstruts-config.xmlの属するモジュールの範囲でしか例外をキャッチできない(キャッチしない)が、
web.xmlのerror-pageの方はそこで漏れた例外も全て対象となる。
(Strutsと無関係に処理するようなもの(例えばフィルター)での例外は、error-pageでしかキャッチできない)
Strutsのhtml:errorsタグを利用したエラーページへ遷移させる場合、
error-pageでキャッチした方はStruts用のデータが入っているとは限らない為、注意が必要となる。