左にメニューがあって、右にコンテンツ・・・というようなレイアウトを使う場合、tilesを使えば、画面の構成要素の定義ができる。また、継承を使って、画面の一部分だけ変更する・・・という処理も可能。
インストール
pluginとしてstruts-config.xmlに記述する。
<plug-in className="org.apache.struts.tiles.TilesPlugin"> <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml" /> </plug-in>
web.xmlのActionServletに以下のパラメタを追加。
<init-param> <param-name>chainConfig</param-name> <param-value> org/apache/struts/tiles/chain-config.xml </param-value> </init-param>
レイアウト用JSPの書き方
レイアウト用のJSPにはtailsタグを使ってインクルードする箇所を定義。
<%@ taglib uri="http://struts.apache.org/tags-tiles" prefix="tiles" %> <tiles:insert attribute="header" flush="true" /> <tiles:insert attribute="content" flush="true" /> <tiles:insert attribute="footer" flush="true" />
attribute属性で指定した名前に対して、tiles-defs.xmlでどのJSPをインクルードするかを指定する。上記ではHTMLを使わずに書いているが、Tableタグなどを使ってレイアウトを決めておけば、「メニューのある画面」などが簡単にできる。
tiles-defs.xml
インサートするJSPを定義する。
XML宣言
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 1.3//EN" "http://struts.apache.org/dtds/tiles-config_1_3.dtd">
definition
定義名とその定義で使うJSPファイルを指定する。
<definition name="layout" path="/Resources/jsp/Layout.jsp"> <put name="header" value="/Resources/jsp/Header.jsp" /> <put name="content" value="/Resources/jsp/Main.jsp" /> <put name="footer" value="/Resources/jsp/Footer.jsp" /> </definition>
definitionのname属性にはtilesのページ定義名を指定する。これはforwardで指定される名前に対応するため、以下のようにすればこの定義が呼ばれ、Layout.jspに遷移する。
<action-mappings> <action path="/LoginAction" type="com.daipresents.struts135.login.LoginAction" name="LoginForm" scope="request"> <forward name="success" path="layout" /> <forward name="login" path="/login/login.jsp" /> </action>
definitionを構成する要素をputタグで指定する。
putのname属性にはJSPのtilesタグで指定したattributeを指定する。上の場合だとheader属性部分に「/Resources/jsp/Header.jsp」がインクルードされる。
継承して一部分だけ変更したい場合は以下のように書く。
<definition name="layout" path="/WEB-INF/jsp/layout.jsp"> <put name="header" value="/WEB-INF/jsp/header.jsp" /> <put name="menu" value="/WEB-INF/jsp/menu.jsp" /> <put name="content" value="" /> <put name="footer" value="/WEB-INF/jsp/footer.jsp" /> </definition> <definition name="regpage" extends="layout"> <put name="content" value="/WEB-INF/jsp/reg.jsp" /> </definition>
これならばcontent部分にReg.jspがputされる以外は継承元のページが使われる。
tiles:insertで例外が発生した場合
ディレクティブでerrorPage属性を指定しても、そのページが表示されない。insert元のJSPがすでに出力を開始しているので、
insert部分でエラーがでても、すでに出力された部分は表示されてしまう。errorPageで指定しても、既に出力された部分に加えて、エラーペー
ジのJSPが表示されるわけだ。
上記がその画像。layout.jspでtilesを使ってinsertしているのだけれど(テーブルの部分)layout.jspも表示されているのがわかる。
tilesを使うとinsert先でエラーが発生した場合
- insert先のerrorPage属性が有効
- insert先でerrorPage属性を指定しない場合はinsert元のerrorPage属性が有効
- insert元のページにエラーページがinsertされてしまう
となる。
web.xmlのerror-pageを使ってもstruts-config.xmlのglobal-exceptionsを使っても無理。これ、
バグじゃないかな?しかし、解決方法を発見。struts-config.xmlのexceptionタグの「SILENT_IF_COMMITTED」
というプロパティを使えば、ちょっと改善される。
- SILENT_IF_COMMITTED
- デフォルトはtrue。trueの場合、エラー時に何も表示しない。falseに設定すると、エラーページが表示される。pathにはglobal-forwardの名前は使えないのでパスをちゃんと指定すること。
<global-exceptions> <exception key="errors.required" type="java.lang.Exception" path="/WEB-INF/jsp/error/50XError.jsp" > <set-property key="SILENT_IF_COMMITTED" value="false" /> </exception> </global-exceptions>
参考:http://itpro.nikkeibp.co.jp/article/COLUMN/20060408/234852/?ST=lin-server&P=5
web.xmlに
<error-page> <exception-type>java.lang.Exception</exception-type> <location>/WEB-INF/jsp/error/error50X.jsp</location> </error-page>
としていると、SILENT_IF_COMMITTEDがtrueでもfalseでもなにも表示されずweb.xmlの設定が勝ってしまう。