Struts2第四天,正如預期Struts2的內容還沒有講完,還需要再加一天課。按照正常的授課方式,Struts2在四天內是可以講完的,但這可能是老張最后一次講Struts2,所以他要講得細致些。
今天的重點內容是Struts2的表單錯誤信息排版、Struts2中的FreeMark、和Struts2中的UI標簽。老張計的比較細致,我做總結就不做的那么細致了。
一、Struts2的表單錯誤信息排版
Struts2的表單錯誤信息排版是一個比較常見的問題,但網給所見到的解決方案似乎并不正統。老張給出了他的解決方法。
通過之前的學習,我們知道Struts2中的大部分數據交互操作是由ValueStack來完成的。錯誤信息也是如此。我們在后臺使用配置文件校驗或硬編碼校驗,Struts2將錯誤信息存放在類型為Map的fieldErrors對象中。
我們可以在頁面表單字段的后邊添加此錯誤信息,比如在user.name表單字段后邊添加<s:property value="fieldErrors['user.name'][0]"/>,這樣錯誤信息可以顯示在對應的字段后邊。這是針對我們使用非struts2的ui標簽時(使用提html的ui標簽)。但這里有一個問題,如果我的表單字段特別的多,難道我要手動為每個字段添加一個這樣的錯誤信息,這多少有些麻煩,而且以后字段有什么變化還需要行動更改...。
Struts2在各方面都做的非常細致和人性化,Struts2的UI標簽等主要是使用FreeMark來實現的。Struts2使用FreeMar來實現模板和主題,那么我們回顯表單數據和錯誤信息也可以使用FreeMark來實現。此時我們的表單需要使用struts-tags提供的標簽來定義,然后我們修改它的ftl模板文件。
下面我們看看一下應該如何修改ftl模板文件,我們以UI標簽<s:textarea>為例。Struts2的模板文件存在哪?在Struts2的核心包中的template.xhtml中,textarea.ftl文件內容:
<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" /> <#include "/${parameters.templateDir}/simple/textarea.ftl" /> <#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" /> |
我們只需修改 controlheader.ftl和controlfooter.ftl即可,難道我們需要修改Struts2核心包中的內容?當然不用,這一點Struts2已經為我們考慮到了。我們將這兩個文件解壓縮并放到WebRoot目錄下的”template/xhtml”目錄,必須是xhtml目錄。看default.properties文件中的這斷配置:
### Standard UI theme ### Change this to reflect which path should be used for JSP control tag templates by default struts.ui.theme=xhtml struts.ui.templateDir=template #sets the default template type. Either ftl, vm, or jsp struts.ui.templateSuffix=ftl |
Struts2會先到我們的WebRoot目錄搜索相關ftl文件,如果沒有才到自己的包中找。
我們的目標,要使用Struts2的UI標簽并將錯誤信息顯示在標簽的旁邊。所以我們修改這兩個文件的內容為:
controlheader.ftl
<#-- Only show message if errors are available. This will be done if ActionSupport is used. --> <#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/> <#if parameters.labelposition?default("") == 'top'> <td align="left" valign="top" colspan="2"><#rt/> <#else> <td class="tdLabel"><#rt/> </#if> <#if parameters.label??> <label <#t/> <#if parameters.id??> for="${parameters.id?html}" <#t/> </#if> <#if hasFieldErrors> class="errorLabel"<#t/> <#else> class="label"<#t/> </#if> ><#t/> <#if parameters.required?default(false) && parameters.requiredposition?default("right") != 'right'> <span class="required">${stack.findValue("getText('requiredmark')")}</span><#t/> </#if> ${parameters.label?html}<#t/> <#if parameters.required?default(false) && parameters.requiredposition?default("right") == 'right'> <span class="required"><@s.text name="requiredmark"></@s.text></span><#t/> </#if> ${parameters.labelseparator?default(":")?html}<#t/> <#include "/${parameters.templateDir}/xhtml/tooltip.ftl" /> </label><#t/> </#if> </td><#lt/> <#-- add the extra row --> <#if parameters.labelposition?default("") == 'top'> </tr> <tr> </#if> |
controlfooter.ftl
${parameters.after?if_exists}<#t/> </td><#lt/> <#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/> <#if hasFieldErrors> <td ><#rt/> <#list fieldErrors[parameters.name] as error> <span class="errorMessage">${error?html}</span><#t/> </#list> </td><#lt/> </#if> <#-- if the label position is top, then give the label it's own row in the table --> <tr> </tr> |
至于為什么這么修改,一看便知,我就不多做解釋了。
二、Struts2如何使用Freemarker
Struts2是如何使用Freemarker的?在struts2的核心包中有一個default.properties配置文件,Struts2的默認配置都在這個文件中。有一些配置是開啟的有一些配置是關閉的。我們要想打開被關閉的配置可以在struts.xml中,添加<constant name="配置項名" value="配置項值"></constant>元素。
default.properties中有一個”struts.freemarker.manager.classname=org.apache.struts2.views.freemarker.FreemarkerManager“配置,Struts2是通過FreemarkerManager類來實現對Freemarker的操作的。
通過查看源代碼,我們知道通過調用FreemarkerManager類的buildTemplateModel方法生成一個model對象,然后將這個對象放在ValueStack中提供給Freemarker的引擎使用。model中都包含發哪些數據?Freemark的模板信息自然不用說,它還包含Request、Application、Response等這些在WEB應用中常用到的對象。具體我就不詳細列出了,大家可以查看源代碼。我們在上邊兩個模板文件中使用到的 parameters.name也是存儲在model中的。
在此特別提出一個被叫做UIBean的類型,UIBean就是對應Struts2的UI標簽的對象實體。比如標簽有name、theme、id等數據,這些都會被封裝到UIBean中。Freemarker也正是使用這個東東給我們生成了相應該的頁面文件。
三、Struts2中的UI標簽
關于各UI標簽的詳細使用方式,在此就不做總結了。
在實際開發中有一個重要的問題需要我們解決,比如有一個選擇個人喜好的表單。我們需要通過一個Action的方法(likesUI)將喜好列表提供給頁面,可以讓用戶選擇。但在應用提交選擇進行表單校驗時,用戶提交的數據不合法,我們需要重新返回到用戶選擇的界面。此時,我們需要調用 likesUI,獲取列表將數據提供給用戶選擇的界面。
我們可以在Action中添加”<result name="input" type="chain">likesUI</result>”,使其發生錯誤時直接跳轉到likesUI,我們也需要在likesUI中添加一個 名稱為input的result標簽,但這個標簽的值不能為likesUI,否則會遞歸調用,直到緩存溢出。我們應將它的值指定為likesUI.jsp頁面。但即使指定了這個頁面,Struts2的內部實現方式也不會調用likesUI方法從,不會將數據傳遞給likesUI.jsp頁面,而它直接跳轉到likesUI.jsp頁面。
看來我們不能這么做,通過張老師對源代碼的詳細解析,我們只需要將likesUIAction中的likesUI的方法命名為input(),并只在likeUIAction中添加”<result name="input">/WEB-INF/pages/user/likesUI.jsp</result>“即可。為什么呢?
在表單校驗發生錯誤并使用 chain進行跳轉時,會被chain攔截器給攔截了(ActionChainResult)。然后又會被攔截器validation給攔截了,它再進行表單校驗進還是以前的數據,還是會出錯然后它就直接跳轉到我們指定的頁面了。注意配置文件中的validation:
<interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> |
它忽略請求為 input,back,cancel,browse請求路徑。所以我們需要將我們的方法名定義為 input()。
我只是泛泛而結,如果想了解Struts2的更多細節請下載老張的視頻看吧!
最后送給大家一個Struts2開發用例參考模式圖:

1.用戶申請注冊,打開注冊頁面。
2.用戶提交注冊申請,表單校驗錯誤。
3.表單校驗錯誤不要跳轉到regUser.jsp頁面,而是應該跳轉到RegUserUI這個Action方法。
4.用戶提交注冊申請,表單校驗通過。
5.表單校驗通過,調用RegUser這個Action方法進行注冊。
6.注冊成功后,不要跳轉到list.jsp頁面。而是應該調用ListAction這個Action方法。
7.ListAction獲取所有用戶信息后,跳轉到list.jsp。
一定要記得老張還有一天的Struts2的課程,下一次課程的重點內容應該是Struts2的文件上傳與下載,Struts2的防止表單重復提交,Struts2與Spring、AJAX整合,Struts2的插件。
接下來的課程內容讓我等的好久啊——Android!雖然聽學習過的同學們說十分簡單,但我還是迫不及待的想Android的一睹真容。我想很多人都是這樣吧!那就關注我接下來6天課程的總結日志吧!