百度商桥网站,郑州有做网站的公司没,淮安建设企业网站,做门户网站需要学什么软件这次#xff0c;我想与您分享我最近从JSF 2.2功能中学到的知识。 为此#xff0c;我决定创建一个简单的ajax#xff0c;可滚动的延迟加载数据表。 请注意#xff0c; 绝不这是相当大的库如Primefaces #xff0c; RichFaces的或ICEFaces的 。 这只是为了告诉您我学到了什… 这次我想与您分享我最近从JSF 2.2功能中学到的知识。 为此我决定创建一个简单的ajax可滚动的延迟加载数据表。 请注意 绝不这是相当大的库如Primefaces RichFaces的或ICEFaces的 。 这只是为了告诉您我学到了什么。 当然如果您愿意没有人可以阻止您使用它。 这个概念 请允许我先告诉您这个概念或者如果您愿意的话请告诉您这种情况。 实际上非常简单。 我们有一个Customer实体的列表基本上我们将实现一个数据表该表是可滚动的可以延迟加载列表并使用ajax。 注意我假设您对JPA和EJB感到满意因此尽管我可能在这里和那里提到它们但在本文中不再讨论。 使用模板 就像任何JSF应用程序一样我也从使用模板开始。 将模板与Netbeans一起使用非常容易。 只需选择选项Facelets模板并选择您的布局即可。 注意Netbeans还会生成两个样式表cssLayout.css和default.css 。 还要注意在新生成的模板中它们使用文件位置进行定位如下所示 h:headmeta http-equivContent-Type contenttext/html; charsetUTF-8 /link href./../resources/css/default.css relstylesheet typetext/css /link href./../resources/css/cssLayout.css relstylesheet typetext/css /titleFacelets Template/title
/h:head 我对默认模板进行了许多修改。 首先启动应用程序服务器时遇到一个问题即样式表未正确加载。 因此要解决此问题我使用了JSF Resource Locator Lubke 2008。 我还创建了每个子页面即页眉菜单和页脚。 如果未指定则它们充当默认值 。 因此我的页面集合如下 template.xhtml ?xml version1.0 encodingUTF-8 ?
!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
html xmlnshttp://www.w3.org/1999/xhtmlxmlns:uihttp://java.sun.com/jsf/faceletsxmlns:hhttp://java.sun.com/jsf/htmlh:headmeta http-equivContent-Type contenttext/html; charsetUTF-8 /h:outputStylesheet librarycss namedefault.css /h:outputStylesheet librarycss namecssLayout.css /titleFacelets Template/title/h:headh:bodydiv idtopui:insert nameheaderui:include srcheader.xhtml //ui:insert/divdivdiv idleftui:insert namemenuui:include srcmenu.xhtml //ui:insert/divdiv idcontent classleft_contentui:insert namecontent!-- empty content goes here --/ui:insert/div/divdiv idbottomui:insert namebottom ui:include srcfooter.xhtml //ui:insert/div/h:body
/html 注意我使用h:outputStylesheet而不是使用文件定位器./../resources/css/default.css 。 使用这种方法只需将所有资源放在resources目录中并通过属性library指向包含您的资源的文件夹来指向它即可。 因此例如h:outputStylesheet librarycss namedefault.css /确实是在resources/css/default.css位置查看文件。 header.xhtmlfooter.xhtmlmenu.xhtml ?xml version1.0 encodingUTF-8?
!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
html xmlnshttp://www.w3.org/1999/xhtml xmlns:uihttp://java.sun.com/jsf/faceletsbodyui:composition!--I created each file for header, footer and menu, but I simply listthem here just to show you--h1Default Header/h1!-- h1Default Menu/h1 --!-- h1Default Footer/h1 --/ui:composition /body
/html 接下来使用模板。 因此我们创建一个名为customers.xhtml的文件来使用它。 customer.xhtml ?xml version1.0 encodingUTF-8 ?
!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
html xmlnshttp://www.w3.org/1999/xhtmlxmlns:uihttp://java.sun.com/jsf/faceletsxmlns:hhttp://java.sun.com/jsf/htmlbodyui:composition template./common/template.xhtmlui:define namecontenth:outputText valueList of customers goes here!!! //ui:define/ui:composition/body
/html 然后您可以运行应用程序服务器并通过http://the path to your application/customers.jsf访问该页面。 输出应如下图所示。 添加设施以创建客户 首先在模板中让我们添加一个工具以在customers.xhtml中添加customers.xhtml 。 我们可以简单地使用JSF ManagedBean来做到这一点。 但是Core Javaserver Faces第三版建议 对于可以在JSF页面中使用的bean有两种单独的机制CDI bean和JSF管理的bean是历史上的意外。 我们建议您使用CDI bean除非您的应用程序必须在诸如Tomcat之类的普通servlet运行程序上运行。 GearyHorstmann2010年 按照建议从现在开始我将使用CDI bean。 在实际的应用程序中我确信还有很多数据要捕获。 但是在此示例中让我们仅捕获客户的姓名。 基本上我们需要一个Model和一个Controller 。 因此让我们首先创建这些类。 CustomerData.java package id.co.dwuysan.customer;import javax.enterprise.inject.Model;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;Model
public class CustomerData {NotNullSize(min 1, max 50)private String name;public String getName() {return name;}public void setName(String name) {this.name name;}void clear() {setName(null);}
} CustomerData.java package id.co.dwuysan.customer;import id.co.dwuysan.service.CustomerService;
import javax.ejb.EJBException;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.inject.Inject;
import javax.inject.Named;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;Named
public class CustomerRegistationAction {Injectprivate CustomerData customer;Injectprivate CustomerService customerService;public void register(ActionEvent event) {try {// calls EJB and do registration here} catch (EJBException e) {FacesContext.getCurrentInstance().addMessage(event.getComponent().getClientId(), new FacesMessage(e.getMessage()));throw new AbortProcessingException(e.getMessage());}this.customer.clear();}
} 注意在这种情况下我们使用Named注释。 由于我们没有给它任何范围注释因此默认为RequestScoped BalusC 2011a。 下一步是修改我们的customers.xhtml以使用这些类以便我们可以注册客户。 customer.xhtml ?xml version1.0 encodingUTF-8 ?
!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
html xmlnshttp://www.w3.org/1999/xhtmlxmlns:uihttp://java.sun.com/jsf/faceletsxmlns:fhttp://java.sun.com/jsf/corexmlns:hhttp://java.sun.com/jsf/htmlxmlns:ezhttp://java.sun.com/jsf/composite/ezcompbodyui:composition template./common/template.xhtmlui:define namecontentf:view transienttrueh:formh:panelGrid columns3h:outputLabel fortxtCustomerName valueCustomer name /h:inputText idtxtCustomerName value#{customerData.name} /h:message fortxtCustomerName styleClasserror /div /h:commandButton idcmdRegisterCustomer valueSubmit actioncustomers actionListener#{customerRegistationAction.register} /h:message forcmdRegisterCustomer styleClasserror //h:panelGrid/h:form/f:view/ui:define/ui:composition/body
/html 好的一旦完成您就可以注册客户。 屏幕应如下所示。 定义“合同” 这部分是真正的交易。 我所说的“合同”不是实际的合同本身。 相反我指的是我们首先设计Facelet xhtml的方式这将驱动实际的后备bean类。 因此让我们首先概述一下需求 记录应在表中分页并从数据库中延迟加载 用户应该能够选择一个页面中显示多少条记录 用户应该能够查看当前页面是什么页面总数和记录 用户应该能够滚动浏览下一个和上一个记录 使用AJAX 在一个应用程序中必然会有很多清单。 因此前进的最佳方法是创建一个易于重用的组件。 由于组件本身由许多其他组件组成因此我相信此功能正式称为复合组件 。 在JSF 1.x时代这非常痛苦。 开发人员需要编写许多类/文件。 使用JSF 2.x这非常容易我必须说这非常优雅。 让我们从创建组件开始。 创建复合组件 我将这个组件命名为paginator 。 我相信您会找到很多关于如何执行此操作的解释因此我将跳过“说明”部分仅向您展示我的操作。 我在resources/ezcomp目录下创建了一个文件paginator.xhtml 。 因此稍后我将使用命名空间xmlns:ezhttp://java.sun.com/jsf/composite/ezcomp来引用此组件。 让我们继续进行paginator.xhtml的实际实现。 请参考以下资源然后我将逐步指导您。 paginator.xhtml ?xml version1.0 encodingUTF-8 ?
!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
html xmlnshttp://www.w3.org/1999/xhtmlxmlns:cchttp://java.sun.com/jsf/compositexmlns:hhttp://java.sun.com/jsf/htmlxmlns:fhttp://java.sun.com/jsf/core!-- INTERFACE --cc:interfacecc:attribute namepaginateModel / !-- 01 --/cc:interface!-- IMPLEMENTATION --cc:implementation!-- 02 --h:inputHidden value#{cc.attrs.paginateModel.sortField} /h:inputHidden value#{cc.attrs.paginateModel.ascending} /h:inputHidden value#{cc.attrs.paginateModel.page} /!-- 03 --h:panelGrid columns2 cellpadding5 cellspacing5h:outputLabel valueRows-per-page /h:selectOneRadio value#{cc.attrs.paginateModel.rowsPerPage}f:selectItem itemValue5 itemLabel5 /f:selectItem itemValue10 itemLabel10 /f:selectItem itemValue20 itemLabel20 /f:selectItem itemValue100 itemLabel100 /f:ajax executeform renderform listener#{cc.attrs.paginateModel.updateRowsPerPage} //h:selectOneRadio/h:panelGrid!-- pagination --h:panelGrid columns3 cellpadding5 cellspacing5!-- 04 --h:commandLink value actionListener#{cc.attrs.paginateModel.navigatePage(false)} styledisplay: #{cc.attrs.paginateModel.page gt 1 ? block : none}f:ajax executeform renderform //h:commandLink!-- 05 --h:outputLabel value#{cc.attrs.paginateModel.page} ⁄ #{cc.attrs.paginateModel.totalPages} /!-- 06 --h:commandLink value actionListener#{cc.attrs.paginateModel.navigatePage(true)} styledisplay: #{cc.attrs.paginateModel.page lt cc.attrs.paginateModel.totalPages ? block : none}f:ajax executeform renderform //h:commandLink/h:panelGridcc:insertChildren /!-- 07 --br /!-- 08 --h:outputFormat valueThere are {0} record(s).f:param value#{cc.attrs.paginateModel.recordCount} //h:outputFormat/cc:implementation
/html 下一节将说明我在customers.xhtml提出的每个编号点。 01. cc:attribute和paginatedModel 这部分是此xhtml中的实现以及此组件的客户端/用户之间的interface 。 简而言之将其视为使用此组件时必须提供的参数。 02.隐藏参数 现在这部分有很多解释。 首先我需要快进一点以告诉您我正在使用RequestScoped bean支持记录列表。 还要注意的另一件事是我实际上使用了f:view transienttrue 这是JSF 2.2中可用的功能因此使该页面变为无状态。 如果您在浏览器中开源则状态现在为 input typehidden namejavax.faces.ViewState idj_id1:javax.faces.ViewState:0 valuestateless autocompleteoff / 由于此页面是无状态的因此您需要在两次调用之间管理自己的状态Riem 2013。 因此使用隐藏参数。 想象一下假设您正在显示100页中的第4页并且用户决定导航到下一页因为它是无状态的所以您需要知道现在是哪一页无论当前显示是按升序还是降序列出以及目前的排序方式。 03.每页行数选择 这一部分很不言自明只有一部分。 基本上我们列出了供用户选择的选项以供选择以每页显示多少条记录。 当用户选择时我们需要使用AJAX重新执行查询并更新页面。 因此本节的使用 f:ajax executeform renderform listener#{cc.attrs.paginateModel.updateRowsPerPage} / 本部分的内容基本上是基于用户选择执行方法updateRowsPerPage并更新此form 。 如第02节所述 execute还意味着我们正在考虑这种form所有参数。 04/06。 导航“后退”和“前进” 我将在本节中一起解释04和06部分因为它们非常相似。 让我们从第04部分开始。这基本上将呈现一个链接以允许用户导航Back 。 仅在当前页面不是第一页的情况下我才简单地使用display属性来进行条件渲染否则将无法导航回第一页对吗。 第6部分非常相似条件是仅在当前页面不是最后一页时才呈现。 我要说明的下一部分是单击该页面时的actionListener 。 基本上我们现在知道由于h:inputHidden 参见02节当前页面是什么。 因此使用04和06部分中的两个命令链接我们需要标记这是哪种导航。 为此我只使用布尔值。 最后因为我们想使用AJAX进行导航所以我们还需要使用f:ajax 。 同样与前面的部分有关在form上execute和render原因相同。 05当前页和总页数 这部分只是呈现当前页面和可用页面总数。 不言自明 06见第04节 见第04节 07 insertChildren 尽管我们可以重复使用分页器但我认为创建一个将数据模型自动呈现到表中的组件非常困难。 至少页面设计者需要确定要呈现的列我确信必须有一种神奇的方式以表格方式自动呈现所有内容。也许Oracle ADF Faces会为您做到这一点。无论如何我不必费心找到它。 使用此标记时基本上稍后使用ezcomp:paginator.../ezcomp:paginator 插入之间的任何内容都将在第07部分呈现。考虑一下类似ui:decorate 。 08显示总记录 对于此部分我们只显示总记录。 不言自明。 使用复合组件 现在我们基本上需要使用此复合组件。 因此我们需要如下修改我们的customers.xhtml customer.xhtml ?xml version1.0 encodingUTF-8 ?
!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
html xmlnshttp://www.w3.org/1999/xhtmlxmlns:uihttp://java.sun.com/jsf/faceletsxmlns:fhttp://java.sun.com/jsf/corexmlns:hhttp://java.sun.com/jsf/htmlxmlns:ezhttp://java.sun.com/jsf/composite/ezcomp !-- 01 --bodyui:composition template./common/template.xhtmlui:define namecontentf:view transienttrueh:form idfrmCreateCustomerh:panelGrid columns3h:outputLabel fortxtCustomerName valueCustomer name /h:inputText idtxtCustomerName value#{customerData.name} /h:message fortxtCustomerName styleClasserror /div /h:commandButton idcmdRegisterCustomer valueSubmit actioncustomers actionListener#{customerRegistationAction.register}f:actionListener binding#{listCustomers.sortByDefault} /f:ajax executeform renderform :frmListCustomers / !-- 03 --/h:commandButtonh:message forcmdRegisterCustomer styleClasserror //h:panelGrid/h:formbr /h:form idfrmListCustomers !-- 02 --ez:paginator paginateModel#{listCustomers} !-- 04 --h:dataTable value#{listCustomers.data} varcust !-- 05 --h:columnf:facet nameheaderh:commandLink valueName actionListener#{listCustomers.sort(name)}f:ajax executeform renderform / !-- 06--/h:commandLink/f:faceth:outputText value#{cust.name} //h:column/h:dataTable/ez:paginator/h:form/f:view/ui:define/ui:composition/body
/html 同样我将一步一步地指导您 01命名空间 如前所述由于我们将分页器放置在resources/ezcomp/paginator.xhtml 因此JSF允许我们使用名称空间http://java.sun.com/jsf/composite/ezcomp来引用它。 因此稍后如04所示您可以通过使用ezcomp:paginator来使用新创建的ezcomp:paginator 。 02以自己的形式列出表 让我们跳到第二部分。第二部分显示在此customers.xhtml 我们使用两种形式。 主要是因为我要与表进行交互所以您不希望它影响或受另一种形式的影响在本例中为“创建客户”部分。 让我们说假设我们只对整个customers.xhtml使用一种形式。 单击按钮进行排序第06部分时可能会触发对创建文本框的验证例如客户名称不能为空。 我们不想要那个。 由于第03节中概述的原因我们还需要给此表格起一个名字。 03重新呈现其他表格 这里的意图是每当添加新客户时便能够刷新表。 注意命名容器相对于02节是第二个h:form 。 因此由于“创建客户”和表位于不同的命名容器中因此让我们仅刷新整个第二个表单即可这是通过使用正确的“搜索表达式”完成的。 首先使用“”这意味着JSF将从文档的根目录搜索树BalusC2011b。 04使用我们新创建的复合组件 这就是使用我们新创建的paginator组件的简单方法即通过将适当的参数传递给它此后。 另请参阅paginator.xhtml及其说明。 05实际数据表 这是实际的数据表。 如前所述尽管我们可以创建通用分页器但我认为创建通用表渲染将非常困难。 因此在这种情况下我只想向您展示确定要渲染的列的情况。 需要注意的一件事是我们调用listCustomers.data为数据表提供javax.faces.DataModel 。 基于页面大小排序等此“数据”应该是正确的数据。如果您仍然不明白请不要担心。 在下一节中它将变得更加清晰。 06排序 根据以上要求我们需要实现排序。 这是不言自明的使用f:ajax与前面提到的原因相同。 创建类以支持分页 好的我们已经使用paginator.xhtml创建了“合同/需求”然后在customers.xhtml上使用了它。 我们现在需要的是实现一个支持该功能的类。 我要做的是遍历customers.xhtml和paginator.xhtml 。 您也可以这样做以便您可以轻松理解下面列出的每个要点 首先查看customers.xhtml 该类称为“ listCustomers”。 由于我们正在使用CDI因此需要使用Named将bean暴露给JSF环境。 我们可以创建ListCustomers.java 或在Named批注中填充value 。 过去我将ViewScoped用于此bean。 但是由于我们将JSF的“无状态”功能与f:view transienttrue 因此我们无法再使用ViewScoped 。 这些bean与JSF框架所管理的视图相关。 但是有了这种无状态功能视图总是会被重新创建而这个范围内的bean也会被重新创建Busscher 2013。 因此最好使用的范围是RequestScoped 。 它需要具有返回javax.faces.DataModelT getData() 。 这应该返回要显示的Customer列表。 它需要支持public void sort(final String sortField)以支持标头排序。 String getSortField() boolean isAscending() String getSortField() int getPage()以及它们相应的int getPage()器/设置器的访问器。 这些是必需的与我们的隐藏输入有关。 rowsPerPage访问器/ rowsPerPage器以支持我们的每页行数选择。 它需要支持public void updateRowsPerPage(AjaxBehaviorEvent event) 以便我们可以基于用户的每页行数选择来更新列表。 它需要支持public void navigatePage(final boolean forward) 。 记录recordCount 无论如何您现在应该可以实现该类。 但是我实现它的方法是将其分为两部分。 如果您考虑一下让我们说以后您的应用程序中有多个列表例如订单列表人员列表发票等。 它们将以相同的方式实现。 我认为创建一个基类然后再用实际实体扩展它是一个更好的主意。 首先是基层。 DataListingSupport.java package id.co.dwuysan.util;import java.io.Serializable;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.DataModel;public abstract class DataListingSupportT extends Serializable implements Serializable {private int recordCount 0;private int totalPages 0;private DataModelT data;private int page 1;private Integer rowsPerPage null;private boolean ascending true;private String sortField;public void navigatePage(final boolean forward) {setPage((forward) ? page : --page);refresh();}public void sort(final String sortField) {setSortField(sortField);setAscending(getSortField().equals(sortField) ? !isAscending() : true);refresh();}public void updateRowsPerPage(final AjaxBehaviorEvent event) {setPage(1); // page must reset to the first onerefresh();}public void refresh() {// hook to populate count and datapopulateCountAndData();// compute total pagessetTotalPages(countTotalPages(getRecordCount(), getRowsPerPage()));}/*** The concreate implementation of this class must perform data retrieval* based on the current information available (accessible via methods such* as {link #getSortField()}, {link #isAscending()}, etc.* p* The implementation is responsible in populating the values for {link #setRecordCount(int)}* and {link #setData(javax.faces.model.DataModel)}*/protected abstract void populateCountAndData();/************************************************************** HELPER(S) */private static int countTotalPages(int totalRecord, int rowsPerPage) {int pageCounter 0;for (int pageCountTracker 0; pageCountTracker totalRecord; pageCounter) {pageCountTracker rowsPerPage;}return pageCounter;}/************************************************* ACCESSORS AND MUTATORS */public int getPage() {return page;}public void setPage(int page) {this.page page;}public boolean isAscending() {return ascending;}public void setAscending(boolean ascending) {this.ascending ascending;}public Integer getRowsPerPage() {return rowsPerPage;}public void setRowsPerPage(Integer rowsPerPage) {this.rowsPerPage rowsPerPage;}public DataModelT getData() {return data;}public void setData(DataModelT data) {this.data data;}public String getSortField() {return sortField;}public void setSortField(String sortField) {this.sortField sortField;}public int getRecordCount() {return recordCount;}public void setRecordCount(int recordCount) {this.recordCount recordCount;}public int getTotalPages() {return totalPages;}public void setTotalPages(int totalPages) {this.totalPages totalPages;}
} 接下来是我们如何扩展该类以创建支持bean以支持Customer列表。 DataListingSupport.java package id.co.dwuysan.customer;import id.co.dwuysan.entity.Customer;
import id.co.dwuysan.service.CustomerService;
import id.co.dwuysan.util.DataListingSupport;
import javax.enterprise.context.RequestScoped;
import javax.faces.model.ListDataModel;
import javax.inject.Inject;
import javax.inject.Named;RequestScoped
Named
public class ListCustomers extends DataListingSupportCustomer {Injectprivate CustomerService customerService;public ListCustomers() {setSortField(name);setRowsPerPage(10);}Overrideprotected void populateCountAndData() {/** This is where we call an EJB (or whatever service layer you have)* to perform data retrieval.** You need to make sure to retrieve the result (paginated, sorted), and* also the total number of records.*/setRecordCount(result.getCount());setData(new ListDataModel(result.getResult()));}
} 因此您看到使用这种方法如果我需要另一种清单即订单清单我们可以轻松扩展DataListingSupport 。 结果 在向您展示全部结果之前我们可能要添加的一件事是在页面显示时从数据库加载所有当前客户的操作。 JSF 2.2添加了一项称为“查看操作”的功能该功能使此操作非常简单McGinn 2011。 所有你需要做的是添加这个f:viewAction后f:view如下 customer.xhtml ?xml version1.0 encodingUTF-8 ?
!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
html xmlnshttp://www.w3.org/1999/xhtmlxmlns:uihttp://java.sun.com/jsf/faceletsxmlns:fhttp://java.sun.com/jsf/corexmlns:hhttp://java.sun.com/jsf/htmlxmlns:ezhttp://java.sun.com/jsf/composite/ezcomp !-- 01 --bodyui:composition template./common/template.xhtmlui:define namecontentf:view transienttrue!-- to load on display of the page --f:metadataf:viewAction transienttrue action#{listCustomers.refresh}//f:metadatah:form idfrmCreateCustomer!-- the rest of the code remains unchanged --/h:form/f:view/ui:define/ui:composition/body
/html 注意我们只是简单地调用DataListingSupport#refresh() 。 viewAction实际上会分析String返回以执行隐式导航。 在这种情况下我们的refresh()方法实际上返回void 因此不执行导航McGinn 2011。 结果应该是这样的 我从纳斯达克100指数中挑选了客户名单。 因此现在您有了一个可滚动可延迟加载的AJAX数据表。 参考文献 BalusC2011a “ netbeans中的JSF 2应用程序中默认的Managed Bean Scope是什么” 堆栈溢出2013年11月6日访问 BalusC2011b “如何在JSF ajax中引用组件 在 2013年11月11日访问的堆栈溢出中 在视图中找不到标识符为“ foo”的组件 BusscherR2013年 “解释了JSF 2.2无状态视图” JSF Corner2013年11月12日访问 Geary DHorstmannC2010年“ Core JavaServer Faces第3版”第3版美国加利福尼亚州Prentice Hall LubkeR2008 “ JSF 2.0新功能预览系列第4部分资源重定位” Oracle.com2013年10月7日访问 McGinnT2011年 “新的JavaServer Faces 2.2功能viewAction组件” Oracle.com2013年11月17日访问 Oracle2013年 “复合组件” Oracle.com2013年11月7日访问 Riem男2013年 “ JSF技巧26 – JSF变得无状态” Java.net2013年11月9日访问 参考 使用JSF 2.2功能从dwuysan博客博客中的JCG合作伙伴 Deny Wuysan 开发了ajax可滚动延迟加载的数据表 。 翻译自: https://www.javacodegeeks.com/2013/11/using-jsf-2-2-features-to-develop-ajax-scrollable-lazy-loading-data-table.html