使用PrimeFaces开发数据导出实用程序

我的日常工作涉及大量使用数据。 我们使用关系数据库来存储所有内容,因为我们依赖于企业级的数据管理。 有时,具有将数据提取为简单格式(例如电子表格)的功能很有用,以便我们可以按需进行操作。 这篇文章概述了我使用PrimeFaces 5.0生成有效且易于使用的基于JSF的数据导出实用程序所采取的步骤。 导出实用程序将生成一个电子表格,其中包括列标题。 用户可以选择要导出的数据库字段以及应该以什么顺序导出。

我们要确保我们拥有一个直观的干净用户界面。 因此,我选择不在屏幕上显示任何数据。 而是,用户界面包含一个PrimeFaces PickList组件,该组件列出了可供选择的不同数据字段,以及一个用于生成导出的按钮。 首先,设置数据库基础结构以使此导出实用程序成为可能。

对于这篇文章,我增强了AcmePools应用程序,该应用程序是通过我在OTN上发布的名为PrimeFaces in the Enterprise的文章开发的 。 导出实用程序允许将客户数据导出到电子表格中。 客户数据包含在NetBeans安装在Apache Derby内的示例数据库中,或者您可以将SQL脚本用于此文章。 在创建此导出实用程序之前,请在您的环境中下载或创建AcmePools项目。

数据导出实用程序分为两部分,第一部分是PrimeFaces PickList组件,供用户选择要导出的字段,第二部分是导出按钮,它将选择的字段内容提取到电子表格中。 最终结果将类似于图1所示的用户界面。

图1:数据导出实用程序

图1:数据导出实用程序

开发PickList组件

首先,创建数据基础结构以支持PickList组件。 它由一个单独的数据库表组成,用于保存您要导出的实体数据的列名和标签,以及一个可选的数据库序列,用于填充该表的主键。 在这种情况下,数据库表名为COLUMN_MODEL,我们用与CUSTOMER数据库表的数据库列名称相对应的实体字段名称填充该表。

-- Add support for data export
create table column_model(
id                  int primary key,
column_name         varchar(30),
column_label        varchar(150));
-- Optional sequence for primary key generation
create sequence column_model_s
start with 1
increment by 1;
-- Load with field (database column) names
insert into column_model values(
1,
'addressline1',
'Address Line 1');insert into column_model values(
2,
'addressline2',
'Address Line 2');insert into column_model values(
3,
'city',
'City');insert into column_model values(
4,
'creditLimit',
'Credit Limit');insert into column_model values(
5,
'customerId',
'Customer Id');insert into column_model values(
6,
'discountCode',
'Discount Code');insert into column_model values(
7,
'email',
'Email');insert into column_model values(
8,
'fax',
'Fax');insert into column_model values(
9,
'name',
'Name');insert into column_model values(
10,
'phone',
'Phone');insert into column_model values(
11,
'state',
'State');insert into column_model values(
12,
'zip',
'Zip');

接下来,创建一个实体类,该实体类可用于从组件内部访问列数据。 如果使用NetBeans等IDE,则可以通过向导轻松完成此操作。 如果使用NetBeans,请右键单击com.acme.acmepools.entity包,然后选择“新建”->“数据库中的实体类”,然后为我们的示例数据库选择数据源。 当表列表填充时,选择COLUMN_MODEL表,如图2所示。最后,选择“下一步”和“完成”以创建实体类。

图2.数据库中的NetBeans IDE新实体类

图2.数据库中的NetBeans IDE新实体类


完成后,名为ColumnModel的实体类应如下所示:

package com.acme.acmepools.entity;import java.io.Serializable;
import java.math.BigDecimal;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlRootElement;/**** @author Juneau*/
@Entity
@Table(name = "COLUMN_MODEL")
@XmlRootElement
@NamedQueries({@NamedQuery(name = "ColumnModel.findAll", query = "SELECT c FROM ColumnModel c"),@NamedQuery(name = "ColumnModel.findById", query = "SELECT c FROM ColumnModel c WHERE c.id = :id"),@NamedQuery(name = "ColumnModel.findByColumnName", query = "SELECT c FROM ColumnModel c WHERE c.columnName = :columnName"),@NamedQuery(name = "ColumnModel.findByColumnLabel", query = "SELECT c FROM ColumnModel c WHERE c.columnLabel = :columnLabel")})
public class ColumnModel implements Serializable {private static final long serialVersionUID = 1L;@Id@Basic(optional = false)@NotNull@Column(name = "ID")private BigDecimal id;@Size(max = 30)@Column(name = "COLUMN_NAME")private String columnName;@Size(max = 150)@Column(name = "COLUMN_LABEL")private String columnLabel;public ColumnModel() {}public ColumnModel(BigDecimal id) {this.id = id;}public BigDecimal getId() {return id;}public void setId(BigDecimal id) {this.id = id;}public String getColumnName() {return columnName;}public void setColumnName(String columnName) {this.columnName = columnName;}public String getColumnLabel() {return columnLabel;}public void setColumnLabel(String columnLabel) {this.columnLabel = columnLabel;}@Overridepublic int hashCode() {int hash = 0;hash += (id != null ? id.hashCode() : 0);return hash;}@Overridepublic boolean equals(Object object) {// TODO: Warning - this method won't work in the case the id fields are not setif (!(object instanceof ColumnModel)) {return false;}ColumnModel other = (ColumnModel) object;if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {return false;}return true;}@Overridepublic String toString() {return "com.acme.acmepools.entity.ColumnModel[ id=" + id + " ]";}}

接下来,为新生成的实体类创建EJB会话bean,以便组件可以查询列数据。 您也可以根据需要使用IDE。 如果使用NetBeans,请右键单击com.acme.acmepools.session包,然后选择“新建”->“实体类的会话Bean”。 对话框打开后,从左侧列表中选择实体类“ com.acme.acmepools.entity.ColumnModel”,然后单击“完成”(图3)。

图3:用于实体类的NetBeans IDE会话Bean对话框

图3:用于实体类的NetBeans IDE会话Bean对话框


创建会话bean之后,添加一个名为findId()的方法,该方法可用于根据指定的列名返回列ID值。 ColumnModelFacade的完整资源应如下所示:

package com.acme.acmepools.session;import com.acme.acmepools.entity.ColumnModel;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;/**** @author Juneau*/
@Stateless
public class ColumnModelFacade extends AbstractFacade {@PersistenceContext(unitName = "com.acme_AcmePools_war_AcmePools-1.0-SNAPSHOTPU")private EntityManager em;@Overrideprotected EntityManager getEntityManager() {return em;}public ColumnModelFacade() {super(ColumnModel.class);}public ColumnModel findId(String columnName){return (ColumnModel) em.createQuery("select object(o) from ColumnModel as o " +"where o.columnName = :columnName").setParameter("columnName", columnName).getSingleResult();}}

接下来,创建一些帮助程序类,这些类将用于在PickList组件中加载和管理数据。 第一个类名为ColumnBean,它用于存储实体数据,然后将其传递给PickList以供使用。 ColumnBean的代码是一个简单的POJO:

package com.acme.acmepools.bean;import java.math.BigDecimal;/**** @author juneau*/
public class ColumnBean {private BigDecimal id;private String columnName;private String columnLabel;public ColumnBean(BigDecimal id, String columnName, String columnLabel){this.id = id;this.columnName = columnName;this.columnLabel = columnLabel;}/*** @return the id*/public BigDecimal getId() {return id;}/*** @param id the id to set*/public void setId(BigDecimal id) {this.id = id;}/*** @return the columnName*/public String getColumnName() {return columnName;}/*** @param columnName the columnName to set*/public void setColumnName(String columnName) {this.columnName = columnName;}/*** @return the columnLabel*/public String getColumnLabel() {return columnLabel;}/*** @param columnLabel the columnLabel to set*/public void setColumnLabel(String columnLabel) {this.columnLabel = columnLabel;}}

PickList组件需要使用PrimeFaces DualListModel来访问和更新数据。 因此,我们必须实现一个类,该类可用于将实体数据强制到ColumnBean POJO中,然后将其存储到DualListModel中,以便PickList组件可以利用它。 在下面的名为PickListBean的类中,构造函数接受作为实体数据的List <ColumnModel>作为参数,执行强制转换,然后将其存储到DualListModel <ColumnBean>集合中,以供组件使用。

package com.acme.acmepools.bean;/**** @author juneau*/import java.util.ArrayList;
import java.util.List;
import com.acme.acmepools.entity.ColumnModel;import org.primefaces.model.DualListModel;public class PickListBean {private DualListModel<ColumnBean> columns;private List<ColumnBean> source = null;private List<ColumnBean> target = null;public PickListBean(List<ColumnModel> columnModelList) {//Columns  source = new ArrayList<ColumnBean>();target = new ArrayList<ColumnBean>();for(ColumnModel column:columnModelList){ColumnBean bean = new ColumnBean(column.getId(), column.getColumnName(), column.getColumnLabel());source.add(bean);}columns = new DualListModel<ColumnBean>(source, target);}public DualListModel<ColumnBean> getColumns() {return columns;}public void setColumns(DualListModel<ColumnBean> columns) {this.columns = columns;}}

最后,我们需要创建一个控制器类来访问所有这些数据。 为此,请在com.acme.acmepools.jsf包中创建一个名为ColumnModelController的类,并通过使用@Named和@SessionScoped对其进行注释,使其成为CDI托管bean。 使该类实现Serializable。 初始控制器类应如下所示(我们稍后将对其进行更新以包括促进导出的方法):

@Named
@SessionScoped
public class ColumnModelController implements Serializable {@EJBColumnModelFacade ejbFacade;private PickListBean pickListBean;private List<ColumnModel> columns;public DualListModel<ColumnBean> getColumns() {pickListBean = new PickListBean(ejbFacade.findAll());return pickListBean.getColumns();}public void setColumns(DualListModel<ColumnBean> columns) {pickListBean.setColumns(columns);}
}

如您所见,getColumns()方法查询ColumnModel实体,该实体通过PickListBean构造函数填充DualListModel <ColumnBean>。

这将处理数据库基础结构和业务逻辑……现在让我们看一下用于PickList的PrimeFaces组件。 以下摘录来自WebPages / poolCustomer / CustomerExport.xhtml视图,其中包含PickList组件的标记:

<p:panel header="Choose Columns for Export"><p:picklist effect="bounce" itemlabel="#{column.columnLabel}" itemvalue="#{column.columnName}" showsourcecontrols="true" showtargetcontrols="true" value="#{columnModelController.columns}" var="column"><f:facet name="sourceCaption">Columns</f:facet><f:facet name="targetCaption">Selected</f:facet></p:picklist></p:panel>

如您所见,PickList使用columnModelController.columns作为数据,然后使用columnLabel字段显示要导出的实体字段的名称。 源和目标PickList窗口的标题可通过构面进行自定义。 添加导出功能现在,我们已经开发了功能选择列表,我们需要对选定的数据进行一些处理。 在本练习中,我们将使用PrimeFaces DataExporter组件提取数据并将其存储到Excel电子表格中。 实际上,我们需要将DataTable合并到视图中以首先显示数据,然后可以使用DataExporter组件导出驻留在表中的数据。 为了构造将用于显示数据的DataTable,我们需要向ColumnModelController类添加一些方法。 这些方法将使我们能够动态地处理DataTable,以便我们可以根据在PickList中选择的列构造列。 实际上,DataTable将查询所有Customer数据,然后仅显示在PickList中选择的那些数据列。 (我们可以通过添加过滤器来修改此查询,但这超出了本文的范围)。 要向表中加载数据,我们只需调用com.acme.acmepools.jsf.CustomerController getItems()方法即可返回所有数据……public List <Customer> getItems(){if(items == null){items = getFacade()。findAll(); } 退换货品; }…现在,我们将必要的方法添加到ColumnModelController,以便我们可以动态构造表。 首先,添加一个单击“导出”按钮将被调用的方法。 此方法将负责构建当前选择的列列表:

public void preProcess(Object document) {System.out.println("starting preprocess");updateColumns();}

接下来,让我们看一下由preProcess()方法调用的updateColumns()的代码:

/*** Called as preprocessor to export (after clicking Excel icon) to capture* the table component and call upon createDynamicColumns()*/public void updateColumns() {//reset table stateUIComponent table = FacesContext.getCurrentInstance().getViewRoot().findComponent(":customerExportForm:customerTable");table.setValueExpression("sortBy", null);//update columnscreateDynamicColumns();}

updateColumns()方法将UIComponent绑定到JSF视图中的表。 然后,它有能力提供排序(如果选择)。 接下来,让我们看一下被调用的createDynamicColumns()方法。

private void createDynamicColumns() {String[] columnKeys = this.getIncludedColumnsByName().split(",");columns = new ArrayList<>();for (String columnKey : columnKeys) {String key = columnKey.trim();columns.add(new ColumnModel(getColumnLabel(key), key));}}

createDynamicColumns()方法可以完成一些工作。 首先,它从PickList中捕获所有选定的列,并将它们存储到名为columnKeys的String []中。 为此,我们使用名为getIncludedColumnsByName()的帮助程序方法,并以逗号分隔结果。 此方法的源如下,它基本上从PickListBean抓取当前选择的列,并将每个列附加到String上,然后将其返回给调用方。

public String getIncludedColumnsByName() {String tempIncludedColString = null;System.out.println("Number of included columns:" + pickListBean.getColumns().getTarget().size());List localSource = pickListBean.getColumns().getTarget();for (int x = 0; x <= localSource.size() - 1; x++) {String tempModel = (String) localSource.get(x);if (tempIncludedColString == null) {tempIncludedColString = tempModel;} else {tempIncludedColString = tempIncludedColString + "," + tempModel;}}return tempIncludedColString;}

接下来,createDynamicColumns()方法然后使用循环解析String []中的每个选定列,并将它们添加到columnList,后者将用于使用适当的列构造DataTable。

现在,让我们看一下用于构造DataExport实用程序的标记:

<p:datatable id="customerTable" rendered="false" value="#{customerController.items}" var="item" widgetvar="customerTable">                    <p:columns columnindexvar="colIndex" value="#{columnModelController.dynamicColumns}" var="column"><f:facet name="header"><h:outputtext value="#{column.header}"></h:outputtext></f:facet><h:outputtext value="#{item[column.property]}"></h:outputtext></p:columns></p:datatable><hr />
<h:outputtext value="Type of file to export: "><h:commandlink><p:graphicimage value="/faces/resources/images/excel.png"><p:dataexporter filename="customers" id="propertyXlsExport" preprocessor="#{columnModelController.preProcess}" target="customerTable" type="xls"></p:dataexporter></p:graphicimage></h:commandlink>
</h:outputtext>

如您所见,DataTable设置为不呈现,因为我们确实不希望显示它。 相反,我们希望使用DataExporter组件导出其内容。 为了动态构造DataTable,这些列将调用columnModelController.dynamicColumns方法以返回动态列列表。 该方法如下所示:

public List<ColumnModel> getDynamicColumns() {return columns;}

在DataExporter实用程序组件中,将columnModelController.preProcess方法分配给预处理器属性以启动动态列列表。 目标设置为customerTable小部件,该部件是我们根据所选列动态构建的DataTable。 为了将其导出到xls电子表格,必须在项目的Maven POM中添加org.apache.poi依赖项,如下所示:

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.7</version></dependency>

就是这样…现在您应该拥有使用PrimeFaces组件的功能齐全的数据导出实用程序。 使用以下链接可在GitHub上获得完整的资源。 此代码已用NetBeans IDE 8.0编写,并已部署到GlassFish 4.0。 我在该项目中使用了PrimeFaces 5.0。

  • GitHub来源: https : //github.com/juneau001/AcmePools

翻译自: https://www.javacodegeeks.com/2014/12/developing-a-data-export-utility-with-primefaces.html

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

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

相关文章

函数名和变量名重名问题

1.如果输出一个函数名&#xff0c;那么输出的就是这个函数的代码。 function test(){console.log("哈哈");}console.log(test); 2.如果变量名 和函数名 重名会怎么样&#xff1f; //a.如果变量有值&#xff0c;那么输出的就是变量的值。//b.如果变量没有值&#xff…

css3 transition的应用

css3 的transition&#xff1a;允许css属性值在一定的时间区内平滑的过渡。 transition-property&#xff1a;变换延续的时间 transition-duration&#xff1a;在延续时间段 transition-timing-function&#xff1a;变换速度变化 transition-delay&#xff1a;变化延迟时间 a&a…

break和continue的区别

break 1.break 语句可用于跳出循环。 2.break所在的循环体已经结束。 continue 1.continue 语句中断循环中的迭代&#xff0c;如果出现了指定的条件&#xff0c;然后继续循环中的下一个迭代。 2.continue所在的循环体并没有结束。 demo演示 for (i0;i<5;i ){if (i3) br…

Tomcat到Wildfly:配置数据库连接

此摘录摘自《 从Tomcat到WildFly 》一书&#xff0c;您将在其中学习如何将现有的Tomcat体系结构移植到WildFly&#xff0c;包括服务器配置和在其顶部运行的应用程序。 WildFly是完全兼容的Java Enterprise Edition 7容器&#xff0c;与Tomcat相比&#xff0c;它具有更多的可用…

我的开始

今天是我第一天写在博客园写东西&#xff0c;怎么说呢&#xff0c;刚毕业 正着工作呢。一头雾水 不知道怎么办&#xff0c;就从同学那里拷了分简历&#xff0c;也学着写了一份。自己还算满意。不过呢 在智联上投了40多家单位了&#xff0c;只有一家让电话面试。有点不值所错&am…

js 深拷贝和浅拷贝

js 深拷贝和浅拷贝 先举一下项目中遇到的两个例子&#xff1a; 例子1&#xff1a; var json $.parseJSON(data.data); //data.data是后台返回的值 var a json.channels; var b json.channels; console.log(ab)//true 这个例子是浅拷贝&#xff0c;a、b两个对象是完…

在jOOQ之上构建的RESTful JDBC HTTP服务器

jOOQ生态系统和社区正在持续增长。 我们个人总是很高兴看到基于jOOQ构建的其他开源项目。 今天&#xff0c;我们非常高兴为您介绍BjrnHarrtell结合REST和RDBMS的一种非常有趣的方法。 BjrnHarrtell从小就是瑞典的程序员。 他通常在Sweco Position AB上忙于编写GIS系统和集成&a…

Tiny Wings 为什么能迅速成为 iOS App Store 付费应用第一名?

Tiny Wings 不知是有意无意&#xff0c;完美的利用了人的性意识。有节奏感的上上下下&#xff0c;找准G点后毫不犹豫的迎头猛扎下去。期待自己拥有绝佳技巧&#xff0c;不放过任何一次能high起来的机会。飞上天触到云的瞬间high得全身淋漓畅快&#xff0c;连续多触云几次基本上…

node.js 搭建http调取 mysql数据库中的值

首先&#xff0c;我们先在数据库中创建两个表t_news,t_news_type;插入数据&#xff1a; 然后我们再写代码&#xff1a; //加载模块express var express require("express"); var fs require("fs"); //加载路径 var url require("url"); //加…

Spring Caching抽象和Google Guava Cache

Spring为缓存昂贵的方法调用提供了强大的开箱即用支持。 这里详细介绍了缓存抽象。 我的目的是要介绍Spring现在为框架的4.0版本提供的较新的缓存实现之一-使用Google Guava Cache 简而言之&#xff0c;请考虑一种具有几种慢速方法的服务&#xff1a; public class DummyBoo…

NHibernate.3.0.Cookbook第三章第9节的翻译

Using stateless sessions 使用无状态会话 当进行大量数据处理的时候,可能会放弃使用一些高级特性,而使用更接近底层的API来提高性能.在NHibernate中,这种高性能的底层API就是无状态的会话.本节介绍如何使用无状态会话来更新movie对象的价格. 准备 使用第一章的Eg.Core和第二章…

致电以验证您的JavaFX UI的响应能力

最近&#xff0c;Jim Weaver在他的Surface Pro上为演示安装了我的小图片索引应用“ picmodo”&#xff0c;并且GUI变成了垃圾。 显然&#xff0c;Windows Tablet上JavaFX的基本字体大小很高&#xff1a; 我认为&#xff0c;即使调整大小行为和预期一样工作&#xff0c;UI也绝…

上周热点回顾(7.9-7.15)

热点随笔&#xff1a; 2012五大主流浏览器 HTML5 和 CSS3 兼容性大比拼&#xff08;梦想天空&#xff08;山边小溪&#xff09;&#xff09; 原创&#xff1a;让密码不再被遗忘 - 在web中尝试图形口令&#xff01;&#xff08;网无忌&#xff09; 构建一个Outlook风格漂亮界面…

vuex 管理vue-router的传值

假设有这样的一种情况&#xff0c;在两个组件中。一个组件【A】主要是比如说放表格数据&#xff0c;而另外一个组件【B】是专门用来向组件A的表格添加数据的表单。这个时候就是两个兄弟组件之间传递数据了。首先想到的是使用兄弟组件传递数据的方法&#xff1a; 新建一个中间件…

命令行下使用curl,采集数据遇到的问题。

前几天遇到这样一个问题&#xff0c;写了一段php采集程序&#xff0c;里面用到了curl_init()等&#xff0c;在浏览器里可以获得数据&#xff0c;但在命令行里不可以用的php环境是wamp&#xff0c;加载了php_curl&#xff0c; php.ini文件里面加载的&#xff0c;打印phpinfo 也显…

纪事地图和Yahoo Cloud服务基准

总览 Yahoo Cloud Service Benchmark是一种相当广泛使用的基准测试工具&#xff0c;用于测试大量密钥&#xff08;例如1亿&#xff09;和少量客户端&#xff08;即由一台计算机提供服务&#xff09;的密钥值存储。 在本文中&#xff0c;我将研究如何使用Chronicle Map在具有12…

JSP 插入到数据库的数据出现 “SQLServerException: 将截断字符串或二进制数据” 错误解决方案

最近在编写一个小型基于的jsp系统开发。掌握数据库一直感觉还不错。但是今天就出现了一个问题困扰我大半天。后来本来准备睡觉&#xff0c;但是觉得今天不解决这个问题恐怕晚上是“彻夜难眠啊”&#xff01;&#xff01;于是打开电脑&#xff0c;又开始捣腾。遇到问题首先去网上…

c++ 错误处理

void __fastcall TForm1::Button1Click(TObject *Sender) { try { int iEdit1->Text.ToInt(); Edit1->TextAnsiString(10/i); } catch (...) { ShowMessage("Error"); } } 通过 为知笔记 发布转载于:https://www.cnblogs.com/xe2011/archive/2012/07/16/55298e…

使用FizzBu​​zz和Mockito进行单元测试

我有时使用FizzBu​​zz向新手演示单元测试的基础。 尽管FizzBu​​zz确实是一个简单的问题&#xff0c;但是它也可以用于演示更高级的单元测试技术&#xff0c;例如模拟 。 FizzBu​​zz Kata&#xff1a; “ 编写一个程序&#xff0c;打印从1到100的数字。但是&#xff0c;…

前后端分手大师——MVVM 模式

阅读目录简而言之组成部分没有什么是一个栗子不能解决的简而言之 之前对 MVVM 模式一直只是模模糊糊的认识&#xff0c;正所谓没有实践就没有发言权&#xff0c;通过这两年对 Vue 框架的深入学习和项目实践&#xff0c;终于可以装B了有了拨开云雾见月明的感觉。 Model–View–…