Struts2 + Tiles2 架構整合
我們知道 Struts2 提供了 plug-in 可以與 Tiles2 整合, 但此種整合方式是在 struts2 上面暴露 tiles2 的使用方法~如:
<package name="default" extends="tiles-default"> <action name="IndexAction" class="tutoial.IndexAction"> <result name="success" type="tiles">base.definition</result> </action> </package>由此可看到開發時, 需搭配 tiles 樣版對映, 真正要處理的頁面還需參考到 tiles2 的設定檔.
而此篇文章的目的則是想把 layout 方面的控制定位為架構處理. 讓一般的 struts2 程式感覺不到 tiles2 的存在.
因為在一般的應用系統中, layout 通常不多, 而交易程式佔了絕大部份~
不過在進行之前, 還是要先參考如何將官方版的 struts2 + tiles2 環境建立起來~因為我們仍需要 tiles2 這些 jar 檔與設定, 而是改良其在 struts.xml 中的使用方式, 在此就不說明了~
可以參考官方網站所提供的教學連結:
http://www.vaannila.com/struts-2/struts-2-example/struts-2-tiles-example-1.html
以下我們先來看看想要達成的目的:
<package name="main" extends="struts-default"> <result-types> <result-type name="layout1" class="tutoial.MyTilesTemplateResult" /> </result-types> <action name="index" class="tutoial.IndexAction"> <result name="success" type="layout1">/home.jsp</result> </action> </package>
在這裡我們可以看到, IndexAction 處理完之後轉到 success, 將會透過 layout1 的 result-type, 也就是 tutoial.MyTilesTemplateResult 進行處理, 而此 result-type 將會把 /home.jsp 自動引入到 tiles 宣告的 definition 裡.
如此, 寫 IndexAction 時, 就不必考慮 layout 的處理, 只需要處理好與本身程式相關的結果頁面即可. 不會感覺到 tiles 的運作.
所以我們這一段的重點將是此 ResultType 的實作.而後續會再討論到如何透過 struts2 提供的 package 彈性讓寫法更加簡單.
先看看 tiles 的定義檔
<tiles-definitions> <definition name="default" template="/layout.jsp" /> </tiles-definitions>
簡單起見, 我們只宣告了一個 default 的定義檔, 而 template 檔為 layout.jsp
接著看 layout.jsp
<%@page contentType="text/html; charset=UTF-8"%> <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %> <html> <body> <table> <tr><td> This is TOP area.</td></tr> <tr> <td><tiles:insertAttribute name="body"/></td> </tr> <tr><td> This is FOOTER area.</td></tr> </table> </body> </html>
可以看到此layout只包含了TOP與FOOTER,而將頁面放在中間~(屬性為body).
最後來看看ResultType的實作
package tutoial; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import org.apache.struts2.dispatcher.StrutsResultSupport; import org.apache.tiles.Attribute; import org.apache.tiles.AttributeContext; import org.apache.tiles.TilesContainer; import org.apache.tiles.access.TilesAccess; public class MyTilesTemplateResult extends StrutsResultSupport { public MyTilesTemplateResult() { super(); } public MyTilesTemplateResult(String location) { super(location); } @Override public void doExecute(String location, ActionInvocation ai) throws Exception { setLocation(location); String definitionName = "default"; String attributeName = "body"; ServletContext servletContext = ServletActionContext.getServletContext(); HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); TilesContainer container = TilesAccess.getContainer(servletContext); Attribute attribute = new Attribute(location); AttributeContext attributeContext = container.startContext(request, response); attributeContext.putAttribute(attributeName, attribute); container.render(definitionName, request, response); container.endContext(request, response); } }
由以上程式可以得知此 ResultType 將會把定義為 "default" 之定義檔, 將其 attribute 為 "body" 帶入struts.xml上定義的jsp後, 讓 TilesContaier 進行處理.也就達到了我們的目的.
上述程式僅是說明關鍵流程, 讓讀者先了解背後原理.
而我們可以利用 struts2 的 package 機制讓使用上更好用.
首先我們先宣告一個 package, 將該 result-type 設為預設值.如下:
<package name="layout1-default" extends="struts-default"> <result-types> <result-type name="layout" default="true" class="tutoial.MyTilesTemplateResult" /> </result-types> </package> <package name="default" extends="layout1-default"> <action name="index" class="tutoial.IndexAction"> <result name="success">/home.jsp</result> </action> </package>
由此可以看到在 default package 裡面的寫法就像是一般的 struts2 的寫法, 寫程式時更感覺不到 tiles 的運作.是不是更清楚方便了.
當然, 許多的 webapp 有兩種以上的 layout, 此時, 我們可以擴充 MyTilesTemplateResult, 可以帶入參數(definitionName與attributeName).
而 package 可以依多個 layout 來宣告不同的 ResultType 之參數, 再讓每個交易之 package 繼承相對應的 package.
最後達到的結果, 就是讓交易程式不用考慮到 layout 的處理, 切開 layout 與交易處理頁面之關係.
0 Comments:
張貼留言
<< Home