Ajax4jsf 允许开发人员将 Ajax 功能添加到 JSF 应用程序中,而不需要 JavaScript 或用 Ajax 图形部件替换现有的组件。这个包还允许在使用 Java 2D 库时动态地生成图像。Ajax 是一种编程技术,它处理只有页面的一部分需要处理而不需要重新装载整个页面的情况。这种方式的好处包括减少服务器上的处理时间以及加快客户端的响应速度。
与 Tomahawk 相似,Ajax4jsf 提供了一套可以很容易地与 JSF 标记一起使用的标记。在本教程后面对 Developer Forum Signup 示例应用程序进行改进时,将讨论这些标记的示例以及如何将 Ajax4jsf 与 Eclipse 进行集成。接下来,将学习组成这个库的每个组件、在使用它时必须记住的限制以及如何在 Eclipse 项目中添加 Ajax4jsf。
Ajax4jsf 组件被设计成可以轻松地与现有的 JSF 应用程序进行集成,同时提供了改进性能的 Ajax 功能。表 1 中描述了 Ajax4jsf 库中包含的所有标记。
Ajax4jsf 组件 | 描述 |
---|---|
<a4j:actionListener> |
其效果类似于 JSF 中的 <f:actionListener> 或 <f:valueChangeListener> 标记,但是它用于 Ajax 容器。 |
<a4j:actionparam> |
结合了 <f:actionListener> 和 <f:param> JSF 标记的功能。 |
<a4j:commandButton> |
效果类似于被点击时的表单 Submit 按钮,但是呈现为 HTML <input> 标记。 |
<a4j:commandLink> |
效果类似于被点击时的表单 Submit 按钮,但是呈现为 HTML <a> 锚标记。 |
<a4j:loadBundle> |
装载当前视图的本地化资源束。 |
<a4j:mediaOutput> |
允许创建动态生成的内容。 |
<a4j:outputPanel> |
在页面上创建一个启用 Ajax 的部分,允许这个区域中的内容重新呈现(即使导致 Ajax 请求的组件没有专门提到这个区域)。 |
<a4j:page> |
呈现完整的 HTML 页面结构。但是,它必须是 JSF <f:view> 标记的第一个和惟一的子元素,在它外边不能有 HTML 代码。 |
<a4j:region> |
决定 JSF <f:view> 的哪个部分将通过为相关联的 Ajax 请求提供内容来处理。这会只更新页面中需要更新的部分,从而改进性能。 |
<a4j:status> |
通过指出请求何时开始或结束,提供关于指定区域的 Ajax 请求的客户端状态。 |
<a4j:support> |
将 Ajax 功能添加到与 JSF 相关的组件中。这个标记可能是最常用的。 |
根据场景,某些组件会比其他组件更常用。接下来,将学习在使用 Ajax4jsf 时必须记住的条件。
例子
<%@ taglib uri="/WEB-INF/ajax4jsf.tld" prefix="a4j"%> <html> <a4j:loadBundle basename="com.jci.fi.application.cbs.resources.cbsLiteResources" var="rb" /> <head> <h:form id="childContractForm"> <h:panelGrid columns="2" columnClasses="widthCol200px,widthCol200px"> <h:outputText value="#{rb['label.branch']}" styleClass="setLabel" /> <h:panelGroup id="childBranch"> <a4j:region> <h:panelGroup id="branchInp1" style="display:table-cell;vertical-align:middle;"> <h:inputText id="branch" styleClass="setText branch" value="#{prebookFacesBean.currentChildContract.jciBranchNumber}" size="3" maxlength="3" onblur="handleBranchChange();"></h:inputText> <h:inputHidden id ="branchOrgid" value ="#{prebookFacesBean.dataBean.executingBranch.orgId}"></h:inputHidden> <!--end Willie 7/12/2017 2:13 --> <rich:suggestionbox id="suggestionBoxBranchNbr" styleClass="suggestionBoxBranchNbr" for="branch" suggestionAction="#{areaBean.autocompleteBranchForPreBookingChildContract}" var="branch" fetchValue="#{branch.branchNumber}" minChars="1" status="waitStatusNoBlock" eventsQueue="queueBranch" ignoreDupResponses="true" onselect="refreshChildLob();" shadowOpacity="4" border="1" width="300" height="150" shadowDepth="4" cellpadding="2" nothingLabel="#{rb['message.noBranch']}"> <h:column> <h:outputText value="#{branch.branchNumber}" /> </h:column> <h:column> <h:outputText value="#{branch.branchName}" style="font-style:italic" /> </h:column> <h:column> <h:outputText value=" (#{rb['label.region']}: #{branch.areaNumber})" style="font-style:italic" /> </h:column> </rich:suggestionbox> </h:panelGroup> <h:panelGroup id="branchInp2" style="display:table-cell;vertical-align:middle;"> <h:graphicImage id="branchLookUp" style="cursor: pointer;margin-left: 3px;" value="/images/lookup.gif" alt="#{rb['label.lookUp']}" onclick="javascript:launchABWindow('child');"/> </h:panelGroup> <h:panelGroup id="branchInp3" style="display:table-cell;vertical-align:middle;"> <h:outputText value="Invalid Branch" style="color:red;margin-left:5px;" rendered="#{prebookFacesBean.branchNotFound}"></h:outputText> </h:panelGroup> </a4j:region> </h:panelGroup> <h:outputText value="#{rb['label.lineOfBusiness']}" styleClass="setLabel" /> <h:selectOneMenu id="childLob" styleClass="setText lob" value="#{prebookFacesBean.currentChildContract.jciLineOfBusiness.lob}"> <f:selectItems value="#{prebookFacesBean.lobsListSelectItems}" /> </h:selectOneMenu> <h:outputText value="#{rb['label.contractTypeBL']}" styleClass="setLabel" /> <h:selectOneMenu id="childtype" styleClass="setText type" value="#{prebookFacesBean.currentChildContract.contractType.contractType}"> <f:selectItems value="#{prebookFacesBean.childContractTypesListSelectItems}" /> <a4j:support event="onchange" action="#{prebookFacesBean.changeChildContractType}" ajaxSingle="true" reRender="preenter"></a4j:support> </h:selectOneMenu> <h:outputText value="#{rb['label.contractName']}" styleClass="setLabel" /> <h:inputText id="name" styleClass="setText name" value="#{prebookFacesBean.currentChildContract.contractName}" maxlength="27"></h:inputText> <h:outputText value="#{rb['label.preEnterOpenForCost']}?" styleClass="setLabel" /> <h:selectBooleanCheckbox id="preenter" value="#{prebookFacesBean.currentChildContract.preEnter}" disabled="#{prebookFacesBean.childContractPreenterDisabled}" rendered="#{prebookFacesBean.userCanPreenter}" onclick="isPreenterdChild(this.checked);"></h:selectBooleanCheckbox> <h:outputText value="#{rb['label.no']}" rendered="#{!prebookFacesBean.userCanPreenter}"></h:outputText> </h:panelGrid> <rich:panel id="butnsPn" style="border- 0px; margin: 0px; text-align: center; 99%;"> <a4j:commandButton id="save" status="waitStatus" type="button" styleClass="button" action="#{prebookFacesBean.saveChildContract}" onclick="if(!validateChildContractPopup()) return false;" value="#{rb['button.save']}" reRender="childList,ds" oncomplete="Richfaces.hideModalPanel('childContractMP');"></a4j:commandButton> <h:outputText value=" " escape="false"></h:outputText> <a4j:commandButton id="cancel" type="button" styleClass="button" value="#{rb['button.cancel']}" onclick="Richfaces.hideModalPanel('childContractMP');return false;"></a4j:commandButton> </rich:panel> <a4j:jsFunction ajaxSingle="true" name="refreshChildLob" reRender="childLob, childBranch" action="#{prebookFacesBean.populateLobs}" process="branch"></a4j:jsFunction> </h:form>
<a4j:region> <h:panelGroup id="branchInp1" style="display:table-cell;vertical-align:middle;"> <h:inputText id="branch1" styleClass="setText branch" value="#{prebookFacesBean.contractNumber}" size="3" ></h:inputText> <h:inputText id="branch2" styleClass="setText branch" value="#{prebookFacesBean.contractName}" size="3" ></h:inputText> <h:inputText id="branch" styleClass="setText branch" value="#{prebookFacesBean.psaBranchNumber}" size="3" maxlength="3"></h:inputText> <h:inputHidden id ="branchOrgid" value ="#{prebookFacesBean.dataBean.executingBranch.orgId}"></h:inputHidden> <%-- <h:inputText id="branch1" styleClass="setText branch" value="" size="3" maxlength="3"></h:inputText> <h:inputHidden id ="branchOrgid1" value ="#{prebookFacesBean.dataBean.executingBranch.orgId}"></h:inputHidden> --%> <rich:suggestionbox id="suggestionBoxBranchNbr2" for="branch" suggestionAction="#{areaBean.autocompleteBranchForPreBookingPSAContract}" var="branch" fetchValue="#{branch.branchNumber}" minChars="1" status="waitStatusNoBlock" eventsQueue="queueBranch" ignoreDupResponses="true" shadowOpacity="4" border="1" width="300" height="150" shadowDepth="4" cellpadding="2" nothingLabel="#{rb['message.noBranch']}"> <h:column> <h:outputText value="#{branch.branchNumber}" /> </h:column> <h:column> <h:outputText value="#{branch.branchName}" style="font-style:italic" /> </h:column> <h:column> <h:outputText value=" (#{rb['label.region']}: #{branch.areaNumber})" style="font-style:italic" /> </h:column> </rich:suggestionbox> </h:panelGroup> <h:panelGroup id="branchInp2" style="display:table-cell;vertical-align:middle;"> <h:graphicImage id="branchLookUp" style="cursor: pointer;margin-left: 3px;" value="/images/lookup.gif" alt="#{rb['label.lookUp']}" onclick="javascript:launchABWindow('psa');"/> </h:panelGroup> <h:panelGroup id="branchInp3" style="display:table-cell;vertical-align:middle;"> <a4j:commandButton id="getPSA" action="#{prebookFacesBean.lookupPSAContracts}" reRender="availablePSARes,availablePSANoRes" status="waitStatus" value="#{rb['label.submit']}" style="margin-left: 10px;" type="button" styleClass="button"> </a4j:commandButton> </h:panelGroup> </a4j:region>
根据 Ajax4jsf 文档所述,开发人员必须记住某些限制才能创建正确的 Ajax 和 JSF 应用程序:
- Ajax4jsf 框架并不在页面上追加或删除元素,它只会替换页面上的元素。要想在页面上追加代码,应该使用一个空元素标出它的位置。
- 应该只创建严格的符合标准的 HTML 和 XHTML 代码,不要省略任何必需的元素或属性,因为 Ajax 请求由
XMLHttpRequest
函数以 XML 格式创建。但是,这些请求的 XML 格式可能会避开浏览器中的大多数检验和任何纠正处理。 - 最后,大多数 Ajax4jsf 标记有一个属性,它指定在发出 Ajax 请求之后要处理的元素的 ID。这些元素的 ID 必须匹配在 Ajax4jsf 标记的属性中指定的 ID,只有这样更新才会成功。
既然已经了解了组件和使用 Ajax4jsf 的条件,就需要将这个库添加到 Eclipse 项目中,然后才能对 Developer Forum Signup 应用程序进行改进。