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

web.xml.jsf

这次,我想与您分享我最近从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>

注意,不是使用文件定位器./../resources/css/default.css ,而是使用h:outputStylesheet 。 使用这种方法,只需将所有资源放在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第3建议:

对于可以在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(第三版)”,第三版,美国加利福尼亚州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日访问
  • 里姆,男,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

web.xml.jsf

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

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

相关文章

mysql 并发 锁表_MySQL中的锁(表锁、行锁) 并发控制锁

https://github.com/MrLining/mysql/wiki/MySQL%E4%B8%AD%E7%9A%84%E9%94%81%EF%BC%88%E8%A1%A8%E9%94%81%E3%80%81%E8%A1%8C%E9%94%81%EF%BC%89-%E5%B9%B6%E5%8F%91%E6%8E%A7%E5%88%B6%E9%94%816、 表锁差异MyISAM&#xff1a;只支持表级锁&#xff0c;用户在操作myisam表时&a…

jwt获取token_Koa开发之koa-jwt工作过程

最近的工作是开发一个分布式的服务系统&#xff0c;选用的环境是node开发环境&#xff0c;由于需要全面的进行异步开发所以使用Koa框架&#xff0c;开发Web服务需要对用户进行身份认证&#xff0c;所以就使用koa-jwt&#xff0c;为什么使用token这种方式网上有很多介绍token和s…

c语言大作业_2018 C语言大作业--21_Ekko制作教程

同学们实现的效果&#xff1a;https://www.zhihu.com/video/1066249425780809728以下是开发同学的相关文档&#xff1a;《Ekko》设计报告本组设计并编写的游戏《Ekko》&#xff0c;是一款引用了当下红火的网络游戏《英雄联盟》中的游戏角色Ekko为主角&#xff0c;由本组三名成员…

Nutshell中的Java 8语言功能-第1部分

你好朋友&#xff0c; Java 8发布已经很长时间了&#xff0c;现在越来越多地被使用。 在本文中&#xff0c;我们将讨论以下Java 8主题。 1.功能接口 2&#xff0c;Lambda表达式 3.默认方法 1.功能界面 什么是功能接口&#xff1f; 与一种并且只有一种抽象方法的接口是功能…

做ppt用的小插图_如何用PPT做随机抽奖?

每到年底&#xff0c;每个公司都开始筹备年会活动。年会在员工们最期待的就是抽奖环节了。除了用专门的抽奖软件之外&#xff0c;PPT也可以做随机抽奖。今天就来解锁这个动画的做法。1&#xff0c;先设置好图片和文本&#xff1b;2&#xff0c;选中每一张幻灯片&#xff0c;选择…

mysql 隔离级别 快照_MySql的四种事务隔离级别

一、事务的四大特性(ACID)了解事务隔离级别之前不得不了解的事务的四大特性。1、原子性(Atomicity)事务开始后所有操作&#xff0c;要么全部做完&#xff0c;要么全部不做。事务是一个不可分割的整体。事务在执行过程中出错&#xff0c;会回滚到事务开始之前的状态&#xff0c;…

jsp mysql论坛_使用SSM和ajax做一个简易的论坛-01(简介和建表)

三月底刚学完SSM试着做了个简单的论坛&#xff0c;想分享一下&#xff0c;顺便整理一下自己的收获。一、demo介绍一个具有登录、注册功能&#xff0c;发帖、回帖功能的简易论坛。没有后台系统。设计逻辑类似于贴吧&#xff0c;发帖时自动附带一个一楼。二、使用的框架/库前端&a…

elastic 修改map_Amazon Elastic Map Reduce使用Apache Mahout计算建议

elastic 修改mapApache Mahout是一个“可扩展的机器学习库”&#xff0c;其中包括各种单节点和分布式推荐算法的实现。 在上一篇博客文章中&#xff0c; 我描述了如何在单个节点上实现在线推荐系统来处理数据。 如果数据太大而无法放入内存&#xff08;> 100M首选项数据点&a…

mysql 更新时间加数字_Mysql实战45讲笔记:8、聚合函数count

count(*)的实现方式在不同的MySQL引擎中&#xff0c;count()有不同的实现方式 1. MyISAM引擎把一个表的总行数存在了磁盘上&#xff0c;因此执行count()的时候会直接返回这个数&#xff0c;效率很高&#xff1b; 2. 而InnoDB引擎就麻烦了&#xff0c;它执行count(*)的时候&…

python学生管理系统类图_类图 python

广告关闭 腾讯云11.11云上盛惠 &#xff0c;精选热门产品助力上云&#xff0c;云服务器首年88元起&#xff0c;买的越多返的越多&#xff0c;最高返5000元&#xff01; 我正在研究一个庞大的遗留python类&#xff0c;它有很多方法。 我最终将复杂的方法分解成更小的部分&#x…

简单的测试可以防止最严重的故障

错误处理是软件开发中最困难且被忽略的部分之一&#xff0c;如果系统是分布式的&#xff0c;那么这将变得更加困难。 好的论文写在“ 简单测试可以预防最关键的故障” 主题上。 每个开发人员都应该阅读本文。 我将尝试总结本文的主要内容&#xff0c;但建议阅读该论文以获取有…

sql 两个 in_SQL基础知识——IN运算符

IN的作用IN运算符允许您在WHERE子句中指定多个值。IN运算符是多个OR条件的简写。IN的语法SELECT column_name(s) FROM table_name WHERE column_name IN (value1, value2, ...);或者SELECT column_name(s) FROM table_name WHERE column_name IN (SELECT STATEMENT);示例数据库…

pythonlist循环添加元素_python中 for循环之后 添加元素到列表失败?

import re ls list() dc dict() # 介词、连词、人称代词等自己统计 adverb [i, you, he, she, it, in, on, with, by, for, at, about, under, of, to, and, or, therefore, so, of, a] with open("老人与海.txt", moder, encodingutf-8) as f: lryh f.read() # …

开始协议处理句柄_基于smb协议的wmiexec浅析

前言之前研究过Crackmapexec这款工具&#xff0c;对这个工具基于smb协议的wmiexec执行方法产生的流量进行了分析&#xff0c;网上似乎还没有相关的文章&#xff0c;这里旨在抛砖引玉&#xff0c;简单梳理下整个过程&#xff0c;以初学者的视角&#xff0c;探索流量当中存在的奥…

apache camel_轻量级的开源集成:Apache Camel还是Spring集成?

apache camel首先&#xff0c;为全面披露信息&#xff0c;在过去的1.5年中&#xff0c; 我一直担任 FuseSource&#xff08;现为Red Hat&#xff09; 的顾问&#xff0c;为零售&#xff0c;运输&#xff0c;银行/金融等不同行业的大型和小型公司提供SOA和集成项目支持。我的专长…

科尔达服务101

我今天想写一篇简短的要点文章。 我真的很好奇我能多快出版此书。 所以走吧 这篇文章是关于Corda Services&#xff08;使用Corda 3.2版&#xff09;的。 这些是什么&#xff1f; 作为经常使用Spring的开发人员&#xff0c;我个人会说它们就像Beans。 Spring Beans可以做的还很…

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

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

mysql读写分离 存储过程_基于maxscale的读写分离部署笔记

使用maxscale搭建的读写分离架构&#xff0c;后期还可以再结合MHA做master的故障转移&#xff0c;这样业务层面上不需要做任何的改动即可。基于connect方式的不要使用。从库延迟他还会继续分发请求过去&#xff0c;暂时不适合生产使用。实验演示&#xff1a;目前的主从结构&…

python读书笔记2000_流畅的Python读书笔记

特殊方法的存在是为了Python解释器调用的&#xff0c;你自己并不需要去调用他们&#xff0c;比如说my_object.len()这种写法是没有的&#xff0c;应该使用len(my_object)。在使用len(my_object)的时候&#xff0c;如果my_object是一个自定义类的对象&#xff0c;那么Python会自…

antd 3升级命令_是时候拥有一个你自己的命令行工具了

本篇博客主要介绍了如何使用commander, inquirer以及chalk从零开始&#xff0c;创建属于自己的命令行工具。0. 一分钟体验首先我们先花一分钟的时间&#xff0c;体验一下创建自己的命令行cli工具是什么感觉。0.1. 新建项目目录假如我们的项目名称叫hello-cli&#xff0c;使用如…