JSF 2 简介,第 3 部分: 事件处理、JavaScript 和 Ajax
(转自: http://www.ibm.com/developerworks/cn/java/j-jsf2fu3/)
?
2009 年 8 月 03 日
Java?Server Faces (JSF) 2 专家组成员 David Geary 将在这一期文章中结束这部有关 JSF 2 新特性的技巧 1:组件化我在
清单 1 显示了经过删减的
h:selectOneMenu onchange="submit()" value="#{cc.parent.attrs.location.zoomIndex}" valueChangeListener="#{cc.parent.attrs.location.zoomChanged}" style="font-size:13px;font-family:Palatino"> <f:selectItems value="#{places.zoomLevelItems}"/> </h:selectOneMenu> </h:panelGrid> </h:panelGrid> <h:graphicImage url="#{cc.parent.attrs.location.mapUrl}" style="border: thin solid gray"/> ... </div> ... </composite:implementation> </html>组件的一大优点就是可以使用更有效的替代方法替换它们,同时不会影响到相关的功能。比如,在图 2 中,我使用一个 Google Maps 组件替换了
map
onchange="submit()"value="#{cc.parent.attrs.location.zoomIndex}" valueChangeListener="#{cc.parent.attrs.location.zoomChanged}" style="font-size:13px;font-family:Palatino"> <f:selectItems value="#{places.zoomLevelItems}"/> </h:selectOneMenu> ... <m:map id="map" width="420px" height="400px" address="#{cc.parent.attrs.location.streetAddress}, ..." zoom="#{cc.parent.attrs.location.zoomIndex}" renderOnWindowLoad="false"> <m:mapControl id="smallMapCtrl" name="GLargeMapControl" position="G_ANCHOR_TOP_RIGHT"/> <m:mapControl id="smallMapTypeCtrl" name="GMapTypeControl"/> <m:marker id="placeMapMarker"/> </m:map>要使用 GMaps4JSF 组件,我从 GMaps4JSF 组件集合中使用
login
清单 3
loginAction="#{user.login}" managedBean="#{user}"/> </ui:composition>
login
name, password; public String getName() { name } public void setName(String newValue) { name = newValue } public String getPassword() { return password } public void setPassword(String newValue) { password = newValue } public String login() { "/views/places" } public String logout() { name = password = nameError = null "/views/login" }}清单 4
清单 5 展示了生成
在
cc.attrs.loginPrompt} </div> <!-- FORM --> <h:form id="form"> <h:panelGrid columns="2"> <!-- NAME AND PASSWORD FIELDS --> #{cc.attrs.namePrompt} <h:inputText id="name" value="#{cc.attrs.managedBean.name}"/> #{cc.attrs.passwordPrompt} <h:inputSecret id="password" size="8" value="#{cc.attrs.managedBean.password}"/> </h:panelGrid> <p> <!-- LOGIN BUTTON --> <h:commandButton id="loginButton" value="#{cc.attrs.loginButtonText}" action="#{cc.attrs.loginAction}"/> </p> </h:form> </composite:implementation></html>和
回页首技巧 2:Ajax 化
与非 Ajax HTTP 请求相比,Ajax 请求通常需要额外执行两个步骤:在服务器中对表单进行局部处理,接着在客户机上对 Document Object Model (DOM) 进行局部呈现。
局部处理和呈现
通过将 JSF 生命周期分解为两个不同的逻辑部分 —— 执行和呈现,JSF 2 现在支持局部处理和局部呈现。图 5 突出显示了执行部分:
图 5. JSF 生命周期的执行部分图 6 突出显示了 JSF 生命周期的呈现部分:
图 6. JSF 生命周期的呈现部分将生命周期划分为执行和呈现部分的原理很简单:您可以指定 JSF 在服务器上执行(处理)的组件,以及在返回 Ajax 调用时 JSF 呈现的组件。将使用 JSF 2 中新增的
value="#{cc.parent.attrs.location.zoomIndex}" style="font-size:13px;font-family:Palatino"> <f:ajax event="change" execute="@this" render="map"/> <f:selectItems value="#{places.zoomLevelItems}"/> </h:selectOneMenu> <m:map id="map"...>清单 7
<f:ajax render="map"/> <f:selectItems value="#{places.zoomLevelItems}"/> </h:selectOneMenu> <m:map id="map"...>这演示了使用 JSF 2 向组件添加 Ajax 有多么容易。当然,前面的例子非常简单:我仅仅是在用户选择某个缩放级别时重新绘制了地图而不是整个页面。验证表单中的各个字段等操作要更加复杂一些,因此接下来我将讨论这些用例。
验证
当用户移出某个字段后对字段进行验证并提供即时的反馈,这始终是一个好的做法。例如,在图 7 中,我使用了 Ajax 对名称字段进行了验证:
图 7. Ajax 验证该名称字段的标记如清单 9 所示:
清单 9. 名称字段我再一次使用了
validateName(ValueChangeEvent e) { UIInput nameInput = e.getComponent() String name = nameInput.getValue() if (name.contains("_")) nameError = "Name cannot contain underscores" else if (name.equals("")) nameError = "Name cannot be blank" else nameError = "" } ...}这个修改值的监听程序(
user
多字段验证在前面的小节中,我展示了如何对单一字段执行 Ajax 验证。但是,有些情况下,需要同时对多个字段进行验证。比如,图 8 展示了 places 应用程序同时验证名称和密码字段:
图 8. 验证多个字段我在用户提交表单时同时验证了名称和密码字段,因此对这个例子不需要用到 Ajax。相反,我将使用 JSF 2 的新事件系统,如清单 11 所示:
清单 11. 使用在
validate(ComponentSystemEvent e) { UIForm form = e.getComponent() UIInput nameInput = form.findComponent("name") UIInput pwdInput = form.findComponent("password") if ( ! (nameInput.getValue().equals(VALID_NAME) && pwdInput.getValue().equals(VALID_PASSWORD))) { FacesContext fc = FacesContext.getCurrentInstance() fc.addMessage(form.getClientId(), new FacesMessage("Name and password are invalid. Please try again.")) fc.renderResponse() } } ...}JSF 将一个组件系统事件传递给
回页首技巧 3:展示进度
在
在