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天课程的总结日志吧!