使用JSF 2.2功能来开发可滚动,可延迟加载的Ajax数据表

这次,我想与您分享我最近从JSF 2.2功能中学到的知识。 为此,我决定创建一个简单的ajax,可滚动的延迟加载数据表。

请注意, 绝不这是相当大的库如Primefaces , RichFaces的或ICEFaces的 。 这只是为了告诉您我学到了什么。 (当然,如果您愿意,没有人可以阻止您使用它)。

这个概念

请允许我先告诉您这个概念,或者如果您愿意的话,请告诉您这种情况。 实际上非常简单。

我们有一个Customer实体的列表,基本上,我们将实现一个数据表,该表是可滚动的,可以延迟加载列表并使用ajax。

注意:我假设您对JPA和EJB感到满意,因此尽管我可能在这里和那里提到它们,但在本文中不再讨论。

使用模板

就像任何JSF应用程序一样,我也从使用模板开始。 将模板与Netbeans一起使用非常容易。 只需选择选项Facelets模板并选择您的布局即可。

注意,Netbeans还会生成两个样式表cssLayout.cssdefault.css 。 还要注意,在新生成的模板中,它们使用文件位置进行定位,如下所示:

<h:head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link href="./../resources/css/default.css" rel="stylesheet" type="text/css" /><link href="./../resources/css/cssLayout.css" rel="stylesheet" type="text/css" /><title>Facelets Template</title>
</h:head>

我对默认模板进行了许多修改。

首先,启动应用程序服务器时遇到一个问题,即样式表未正确加载。 因此,要解决此问题,我使用了JSF Resource Locator (Lubke 2008)。

我还创建了每个子页面,即页眉,菜单和页脚。 如果未指定,则它们充当默认值

因此,我的页面集合如下:

template.xhtml

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:ui="http://java.sun.com/jsf/facelets"xmlns:h="http://java.sun.com/jsf/html"><h:head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><h:outputStylesheet library="css" name="default.css" /><h:outputStylesheet library="css" name="cssLayout.css" /><title>Facelets Template</title></h:head><h:body><div id="top"><ui:insert name="header"><ui:include src="header.xhtml" /></ui:insert></div><div><div id="left"><ui:insert name="menu"><ui:include src="menu.xhtml" /></ui:insert></div><div id="content" class="left_content"><ui:insert name="content"><!-- empty content goes here --></ui:insert></div></div><div id="bottom"><ui:insert name="bottom">                <ui:include src="footer.xhtml" /></ui:insert></div></h:body>
</html>

注意,我使用h:outputStylesheet而不是使用文件定位器./../resources/css/default.css 。 使用这种方法,只需将所有资源放在resources目录中,并通过属性library指向包含您的资源的文件夹来指向它即可。 因此,例如<h:outputStylesheet library="css" name="default.css" />确实是在resources/css/default.css位置查看文件。

header.xhtml,footer.xhtml,menu.xhtml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"   xmlns:ui="http://java.sun.com/jsf/facelets"><body><ui:composition><!--I created each file for header, footer and menu, but I simply listthem here just to show you--><h1>Default Header</h1><!-- h1>Default Menu</h1 --><!-- h1>Default Footer</h1 --></ui:composition>	</body>
</html>

接下来,使用模板。 因此,我们创建一个名为customers.xhtml的文件来使用它。

customer.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:ui="http://java.sun.com/jsf/facelets"xmlns:h="http://java.sun.com/jsf/html"><body><ui:composition template="./common/template.xhtml"><ui:define name="content"><h:outputText value="List 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运行程序上运行。

(Geary,Horstmann,2010年)

按照建议,从现在开始,我将使用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 {@NotNull@Size(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 version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:ui="http://java.sun.com/jsf/facelets"xmlns:f="http://java.sun.com/jsf/core"xmlns:h="http://java.sun.com/jsf/html"xmlns:ez="http://java.sun.com/jsf/composite/ezcomp"><body><ui:composition template="./common/template.xhtml"><ui:define name="content"><f:view transient="true"><h:form><h:panelGrid columns="3"><h:outputLabel for="txtCustomerName" value="Customer name" /><h:inputText id="txtCustomerName" value="#{customerData.name}" /><h:message for="txtCustomerName" styleClass="error" /><div /><h:commandButton id="cmdRegisterCustomer" value="Submit" action="customers" actionListener="#{customerRegistationAction.register}" /><h:message for="cmdRegisterCustomer" styleClass="error" /></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:ez="http://java.sun.com/jsf/composite/ezcomp来引用此组件。

分页文件

让我们继续进行paginator.xhtml的实际实现。 请参考以下资源,然后我将逐步指导您。

paginator.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:cc="http://java.sun.com/jsf/composite"xmlns:h="http://java.sun.com/jsf/html"xmlns:f="http://java.sun.com/jsf/core"><!-- INTERFACE --><cc:interface><cc:attribute name="paginateModel" /> <!-- 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 columns="2" cellpadding="5" cellspacing="5"><h:outputLabel value="Rows-per-page" /><h:selectOneRadio value="#{cc.attrs.paginateModel.rowsPerPage}"><f:selectItem itemValue="5" itemLabel="5" /><f:selectItem itemValue="10" itemLabel="10" /><f:selectItem itemValue="20" itemLabel="20" /><f:selectItem itemValue="100" itemLabel="100" /><f:ajax execute="@form" render="@form" listener="#{cc.attrs.paginateModel.updateRowsPerPage}" /></h:selectOneRadio></h:panelGrid><!-- pagination --><h:panelGrid columns="3" cellpadding="5" cellspacing="5"><!-- 04 --><h:commandLink value="<<" actionListener="#{cc.attrs.paginateModel.navigatePage(false)}" style="display: #{cc.attrs.paginateModel.page gt 1 ? 'block' : 'none'}"><f:ajax execute="@form" render="@form" /></h:commandLink><!-- 05 --><h:outputLabel value="#{cc.attrs.paginateModel.page} ⁄ #{cc.attrs.paginateModel.totalPages} " /><!-- 06 --><h:commandLink value=">>" actionListener="#{cc.attrs.paginateModel.navigatePage(true)}" style="display: #{cc.attrs.paginateModel.page lt cc.attrs.paginateModel.totalPages ? 'block' : 'none'}"><f:ajax execute="@form" render="@form" /></h:commandLink></h:panelGrid><cc:insertChildren /><!-- 07 --><br /><!-- 08 --><h:outputFormat value="There 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 transient="true"> ,这是JSF 2.2中可用的功能,因此使该页面变为无状态。 如果您在浏览器中开源,则状态现在为:

<input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="stateless" autocomplete="off" />

由于此页面是无状态的,因此您需要在两次调用之间管理自己的状态(Riem 2013)。 因此使用隐藏参数。 想象一下,假设您正在显示100页中的第4页,并且用户决定导航到下一页,因为它是无状态的,所以您需要知道现在是哪一页,无论当前显示是按升序还是降序列出以及目前的排序方式。

03.每页行数选择

这一部分很不言自明,只有一部分。 基本上,我们列出了供用户选择的选项,以供选择以每页显示多少条记录。 当用户选择时,我们需要使用AJAX重新执行查询并更新页面。 因此,本节的使用:

<f:ajax execute="@form" render="@form" 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> 。 同样,与前面的部分有关在@formexecuterender原因相同。

05当前页和总页数

这部分只是呈现当前页面和可用页面总数。 不言自明

06见第04节

见第04节

07 insertChildren

尽管我们可以重复使用分页器,但我认为创建一个将数据模型自动呈现到表中的组件非常困难。 至少,页面设计者需要确定要呈现的列(我确信必须有一种神奇的方式以表格方式自动呈现所有内容。也许Oracle ADF Faces会为您做到这一点。无论如何,我不必费心找到它)。

使用此标记时,基本上稍后使用<ezcomp:paginator>...</ezcomp:paginator> ,插入之间的任何内容都将在第07部分呈现。考虑一下类似<ui:decorate>

08显示总记录

对于此部分,我们只显示总记录。 不言自明。

使用复合组件

现在,我们基本上需要使用此复合组件。 因此,我们需要如下修改我们的customers.xhtml

customer.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:ui="http://java.sun.com/jsf/facelets"xmlns:f="http://java.sun.com/jsf/core"xmlns:h="http://java.sun.com/jsf/html"xmlns:ez="http://java.sun.com/jsf/composite/ezcomp"> <!-- 01 --><body><ui:composition template="./common/template.xhtml"><ui:define name="content"><f:view transient="true"><h:form id="frmCreateCustomer"><h:panelGrid columns="3"><h:outputLabel for="txtCustomerName" value="Customer name" /><h:inputText id="txtCustomerName" value="#{customerData.name}" /><h:message for="txtCustomerName" styleClass="error" /><div /><h:commandButton id="cmdRegisterCustomer" value="Submit" action="customers" actionListener="#{customerRegistationAction.register}"><f:actionListener binding="#{listCustomers.sortByDefault}" /><f:ajax execute="@form" render="@form :frmListCustomers" /> <!-- 03 --></h:commandButton><h:message for="cmdRegisterCustomer" styleClass="error" /></h:panelGrid></h:form><br /><h:form id="frmListCustomers"> <!-- 02 --><ez:paginator paginateModel="#{listCustomers}"> <!-- 04 --><h:dataTable value="#{listCustomers.data}" var="cust"> <!-- 05 --><h:column><f:facet name="header"><h:commandLink value="Name" actionListener="#{listCustomers.sort('name')}"><f:ajax execute="@form" render="@form" /> <!-- 06--></h:commandLink></f:facet><h: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将从文档的根目录搜索树(BalusC,2011b)。

04使用我们新创建的复合组件

这就是使用我们新创建的paginator组件的简单方法,即通过将适当的参数传递给它(此后)。

另请参阅paginator.xhtml及其说明。

05实际数据表

这是实际的数据表。 如前所述,尽管我们可以创建通用分页器,但我认为创建通用表渲染将非常困难。 因此,在这种情况下,我只想向您展示确定要渲染的列的情况。

需要注意的一件事是,我们调用listCustomers.data为数据表提供javax.faces.DataModel 。 基于页面,大小,排序等,此“数据”应该是正确的数据。如果您仍然不明白,请不要担心。 在下一节中,它将变得更加清晰。

06排序

根据以上要求,我们需要实现排序。 这是不言自明的,使用f:ajax与前面提到的原因相同。

创建类以支持分页

好的,我们已经使用paginator.xhtml创建了“合同/需求”,然后在customers.xhtml上使用了它。 我们现在需要的是实现一个支持该功能的类。

我要做的是遍历customers.xhtmlpaginator.xhtml 。 您也可以这样做,以便您可以轻松理解下面列出的每个要点:

  • 首先,查看customers.xhtml ,该类称为“ listCustomers”。 由于我们正在使用CDI,因此需要使用@Named将bean暴露给JSF环境。 我们可以创建ListCustomers.java ,或在@Named批注中填充value
  • 过去,我将@ViewScoped用于此bean。 但是,由于我们将JSF的“无状态”功能与f:view transient="true" ,因此我们无法再使用@ViewScoped 。 这些bean与JSF框架所管理的视图相关。 但是有了这种无状态功能,视图总是会被重新创建,而这个范围内的bean也会被重新创建(Busscher 2013)。 因此,最好使用的范围是@RequestScoped
  • 它需要具有返回javax.faces.DataModel<T> 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 DataListingSupport<T extends Serializable> implements Serializable {private int recordCount = 0;private int totalPages = 0;private DataModel<T> 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 DataModel<T> getData() {return data;}public void setData(DataModel<T> 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 DataListingSupport<Customer> {@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:viewActionf:view如下:

customer.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:ui="http://java.sun.com/jsf/facelets"xmlns:f="http://java.sun.com/jsf/core"xmlns:h="http://java.sun.com/jsf/html"xmlns:ez="http://java.sun.com/jsf/composite/ezcomp"> <!-- 01 --><body><ui:composition template="./common/template.xhtml"><ui:define name="content"><f:view transient="true"><!-- to load on display of the page --><f:metadata><f:viewAction transient="true" action="#{listCustomers.refresh}"/></f:metadata><h:form id="frmCreateCustomer"><!-- 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数据表。

参考文献

  • BalusC,2011a, “ netbeans中的JSF 2应用程序中默认的Managed Bean Scope是什么?” ,堆栈溢出,2013年11月6日访问
  • BalusC,2011b, “如何在JSF ajax中引用组件? 在 2013年11月11日访问的堆栈溢出中, 在视图中找不到标识符为“ foo”的组件
  • Busscher,R,2013年, “解释了JSF 2.2无状态视图” ,JSF Corner,2013年11月12日访问
  • Geary D,Horstmann,C,2010年,“ Core JavaServer Faces(第3版)”,第3版,美国加利福尼亚州Prentice Hall
  • Lubke,R,2008, “ JSF 2.0新功能预览系列(第4部分)资源重定位” ,Oracle.com,2013年10月7日访问
  • McGinn,T,2011年, “新的JavaServer Faces 2.2功能:viewAction组件” ,Oracle.com,2013年11月17日访问
  • Oracle,2013年, “复合组件” ,Oracle.com,2013年11月7日访问
  • Riem,男,2013年, “ JSF技巧#26 – JSF变得无状态” ,Java.net,2013年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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366543.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何监视ps/查询的性能和使用

可以使用“查询管理”页面监视查询性能和使用情况。您可以获得的一些统计信息包括平均运行时、运行次数和上次运行日期。使用预定义的搜索&#xff0c;还可以选择要检查和报告的查询。查询管理还允许您取消当前在查询管理器和查询查看器中运行的查询&#xff0c;以及启用和禁用…

金融计算机怎么调成链式,FRM金融计算器使用方法

2020FRM考试计算器&#xff1a;想一想FRM一级考试基本上按计算器停不下来&#xff0c;我们就一定要买一个简单易操作的计算器&#xff0c;但是GARP对于FRM考生所使用的计算器是有规定的&#xff1a;所有参加FRM考试的考生必须使用GARP指定的计算器&#xff0c;如果考生在考试期…

参数调优为什么要采样_程序员精进之路:性能调优利器--火焰图

本文主要分享火焰图使用技巧&#xff0c;介绍 systemtap 的原理机制&#xff0c;如何使用火焰图快速定位性能问题原因&#xff0c;同时加深对 systemtap 的理解。让我们回想一下&#xff0c;曾经作为编程新手的我们是如何调优程序的&#xff1f;通常是在没有数据的情况下依靠主…

我是这么理解Vue中的响应式系统的

遇到知识&#xff0c;尤其是复杂的概念&#xff0c;我不能类比的话&#xff0c;我很难接收&#xff08;所以学习很差...&#xff09;。在看了大神染陌同学的Vue源码解析后&#xff0c;我想分享一下我所类比的Vue响应式系统&#xff0c;您得先看他的文章&#xff08;至少看他写的…

图的顺序存储(邻接矩阵存储)【摘录自严长生老师的网站】

图是表达多对多关系的一种数据结构&#xff0c;组成要素为顶点和连接顶点的边。 根据边有无方向可分为有向图和无向图 当边有权重时&#xff0c;升级为有向网和无向网 图在存储时&#xff0c;可采用邻接矩阵&#xff0c;比如下面的无向图&#xff08;A&#xff09;和&#xff0…

Neo4j:使隐式关系成为显式和双向关系

最近&#xff0c;我阅读了Michal Bachman关于 Neo4j中双向关系的文章 &#xff0c;他建议对于某些关系类型&#xff0c;我们对关系的方向不那么感兴趣&#xff0c;因此可以在查询时忽略它。 他使用以下示例显示了Neo Technology和GraphAware之间的合作关系&#xff1a; 两家公…

复旦大学计算机学院博士生王斌,复旦大学计算机科学技术学院博士生刘鹏飞荣获...

计算机科学技术学院发布时间:2017-01-04 小字体 中字体 大字体2016年12月22日,历时七个月选拔的2016年度百度奖学金获奖者揭晓,复旦大学计算机科学技术学院2014级博士生刘鹏飞以其在“自然语言处理与深度学习”上取得的突出成绩,从国内外近百所著名高校数百位竞争者中脱颖而出,…

Deno 兼容浏览器具体指的是什么?

Deno 里面有一句描述&#xff1a;"Aims to be browser compatible"&#xff0c;可以看到 Deno 的目标是兼容浏览器。那么这里的兼容浏览器到底如何是什么意思呢&#xff1f; 我简单谈谈我的理解吧。 首先这里的兼容性肯定不是 Deno 直接在浏览器端运行。因为 Deno …

判断按键值_「正点原子NANO STM32开发板资料连载」第十六章电容触摸按键实验...

1&#xff09;实验平台&#xff1a;ALIENTEK NANO STM32F411 V1开发板2&#xff09;摘自《正点原子STM32F4 开发指南&#xff08;HAL 库版》关注官方微信号公众号&#xff0c;获取更多资料&#xff1a;正点原子第十六章电容触摸按键实验上一章&#xff0c;我们介绍了 STM32F4 的…

将社交登录添加到Spring MVC Web应用程序:注册和登录

本教程的第一部分描述了如何配置Spring Social 1.1.0和Spring Security 3.2.0&#xff0c;但它留下了两个非常重要的问题尚未解答。 这些问题是&#xff1a; 用户如何创建新用户帐户&#xff1f; 用户如何登录&#xff1f; 现在该弄脏我们的手并回答这些问题了。 我们的示例…

实验五 编写、调试具有多个段的程序

&#xff08;1&#xff09;将下面的程序编译、连接&#xff0c;用Debug加载、跟踪&#xff0c;然后回答问题。 ①CPU执行程序&#xff0c;程序返回前&#xff0c;data段的数据为多少&#xff1f; 见下图d 0770:0000 000f结果。 ②CPU执行程序&#xff0c;程序返回前&#xff0c…

手机工商银行怎么转账_工商银行信用卡要哪些申请条件?想成功办理你需要了解这些!...

工商银行信用卡一直是卡友们热议的对象&#xff0c;也有不少卡友问过小白&#xff1a;工商银行信用卡怎么办理&#xff1f;要哪些条件&#xff1f;要等多长时间&#xff1f;那么今天小白就为大家详细的讲解一下工商银行信用卡申请的各种方法和技巧&#xff0c;希望对大家有帮助…

数据可视化的基本原理——视觉通道

数据可视化为了达到增强人脑认知的目的&#xff0c;会利用不同的视觉通道对冰冷的数据进行视觉编码。 我们在数据可视化的时候&#xff0c;一方面&#xff0c;展现可视化对象本身的位置、特性&#xff0c;对应的视觉通道类型是定性或者分类&#xff0c;比如汽车在什么地方、汽…

linux测试地址是否能访问_一个小测试能看出孩子注意力是否集中,提前弥补,上小学会很轻松...

文|秘籍君不少家长虽然重视孩子的教育&#xff0c;却总是习惯“临阵磨枪”&#xff0c;具体体现在&#xff1a;孩子在上幼儿园的前一两个月才开始着急&#xff0c;害怕孩子适应不了幼儿园&#xff1b;孩子上了大班才开始重视“幼小衔接”&#xff0c;却不知道&#xff0c;从孩子…

服务器怎么禁止iis静态文件,如何禁止IIS缓存静态文件

禁止IIS缓存静态文件(png、js、html等)背景&#xff1a;IIS为了提高性能&#xff0c;默认情况下会对静态文件js、html、gif、png等做内部缓存&#xff0c;这个缓存是在服务器iis进程的内存中的。IIS这么做在很大程度上可以提高静态文件的访问性能&#xff0c;在正常情况下只要静…

汇编实验五

一、 二、 三、 四、 第一个 反汇编后发现不行 第二个 发现也不行 第三个 发现代码正确 五、 编写代码如下 调试后查看内存&#xff0c;发现数据相加了 六、 编写代码如下 发现逆序存储成功 七、实验总结 对于代码段的使用有了更加深入的了解。 但是对于代码段内存这块还是不懂…

eclipse RTC下载的代码无android sdk

问题现象&#xff1a; 修复过程&#xff1a; 1.无ADT&#xff0c;安装ADT&#xff08;FQ操作&#xff09; https://dl-ssl.google.com/android/eclipse/ a图 b图 2.下载android sdk a.下载 3.应用到eclipse中去 转载于:https://www.cnblogs.com/liuyj-vv/p/9299913.html

亚马逊免费使用套餐:在EC2 Linux实例上安装Tomcat 7

Amazon Web Services提供了12个月的免费使用期限&#xff0c;使开发人员可以在云中运行任何他们想要的东西。 免费层包括14个服务&#xff0c;其中Web开发人员最关注EC2服务。 EC2是一项服务&#xff0c;通过停止和启动Windows和/或Linux的虚拟实例来提供可调整大小的虚拟计算。…

笔记:隐式转换规则

学习并背诵全文 原始值 类型UndefinedNullStringBooleanNumber值undefinednull所有字符串true false所有数字/NaN 引用类型 Object的成员叫对象&#xff0c;包括Array&#xff0c;Function&#xff0c;Math&#xff0c;Date&#xff0c;JSON&#xff0c;RegExp等除了原始值…

ble连接过程建立_九点之蓝牙连接

蓝牙连接蓝牙连接是如何进入到连接状态呢&#xff0c;首先必须经历前面提到的广播阶段&#xff0c;主端通过扫描到从端的广播来发现这个设备&#xff0c;之后让主端发出连接请求来要求与从端建立连接&#xff0c;便可以进入到连接状态。由于蓝牙连接牵涉的点比较多&#xff0c;…