使用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,一经查实,立即删除!

相关文章

Tomcat到Wildfly:配置数据库连接

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

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

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

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"); //加…

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也绝…

vuex 管理vue-router的传值

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

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…

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

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

Java性能调优调查结果(第三部分)

这是该系列文章的第三篇&#xff0c;我们将分析2014年10月进行的调查的结果。如果您尚未这样做&#xff0c;我建议从该系列的前两篇文章开始&#xff1a; 问题严重性分析和监视域分析 。 这篇文章着重于故障排除/根本原因检测。 本调查部分的背景&#xff1a;意识到性能问题并…

划分树

昨天的杭电多校联合训练热身赛的一道题&#xff0c;求区间的中位数&#xff0c;快排会超时&#xff0c;划分树的模版题。。 划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内&#xff09;序列区间的第k大值 。划分树和归并树都是用线段树作为辅助的…

Canvas事件绑定

canvas事件绑定 众所周知canvas是位图&#xff0c;在位图里我们可以在里面画各种东西&#xff0c;可以是图片&#xff0c;可以是线条等等。那我们想给canvas里的某一张图片添加一个点击事件该怎么做到。而js只能监听到canvas的事件&#xff0c;很明显这个图片是不存在与dom里面…

控件注册 - 利用资源文件将dll、ocx打包进exe文件(转)

很多时候自定义或者引用控件都需要注册才能使用&#xff0c;但是如何使要注册的dll或ocx打包到exe中&#xff0c;使用户下载以后看到的只是一个exe,点击直接运行呢&#xff1f;就像很多安全控件&#xff0c;如支付宝的aliedit.exe那样。 现在介绍一种使用资源文件&#xff0c;将…

Canvas-图片旋转

Canvas-图片旋转 众所周知canvas是位图&#xff0c;你可以在里面渲染你要的东西&#xff0c;不过你只能操作canvas的属性来进行编辑。就是说你并不能操作画进canvas的东西&#xff0c;例如我在canvas里添加一幅画&#xff0c;我现在想将那幅画移动10px&#xff0c;我们并不能直…

CSS3实现多页签图片缩放切换效果

多页签切换效果&#xff0c;图片缩放&#xff0c;鼠标移动到图片上后显示文字内容等等&#xff0c;效果很集中呐 截图如下&#xff1a; 下载地址&#xff1a;http://www.lanrenzhijia.com/js/css3/2012/0718/602.html 预览地址&#xff1a;http://www.lanrenzhijia.com/yulan/2…

Angular使用总结 --- 如何正确的操作DOM

无奈接手了一个旧项目&#xff0c;上一个老哥在Angular项目中大量使用了JQuery来操作DOM&#xff0c;真的是太不讲究了。那么如何优雅的使用Angular的方式来操作DOM呢&#xff1f; 获取元素 1、ElementRef --- A wrapper around a native element inside of a View. 在组件…

非首屏图片延时加载

目标 减少资源加载可以明显的优化页面加载的速度&#xff0c;所以可以减少页面载入时立即下载的图片的数量&#xff0c;以提高页面加载速度&#xff0c;其他的图片在需要的时候再进行加载。 思路 想要实现以上的目标&#xff0c;有几个地方需要思考。 1、如何判断哪些图片需要…

具有链接资源的Spring RestTemplate

Spring Data REST是一个了不起的项目&#xff0c;它提供了一些机制来将基于Spring Data的存储库中的资源公开为REST资源。 使用链接资源公开服务 考虑两个简单的基于JPA的实体&#xff0c;课程和教师&#xff1a; Entity Table(name "teachers") public class Tea…

用户会话,数据控件和AM池

最近&#xff0c;有人问我有关应用程序模块池的有趣问题。 众所周知&#xff0c;AM池包含用户会话引用的应用程序模块实例&#xff0c;这允许会话在后续请求时从池中获取完全相同的AM实例。 如果应用程序中有多个根应用程序模块&#xff0c;那么每个模块都将拥有自己的AM池&am…

用 CSS 实现元素垂直居中,有哪些好的方案?

DIV居中的经典方法 1. 实现DIV水平居中 设置DIV的宽高&#xff0c;使用margin设置边距0 auto&#xff0c;CSS自动算出左右边距&#xff0c;使得DIV居中。 1 div{ 2 width: 100px; 3 height: 100px; 4 margin: 0 auto; 5 } 缺点&#xff1a;需要设置div的宽度 2.…

使用wss和HTTPS / TLS保护WebSocket的安全

是这个博客的第50条提示&#xff0c;是的&#xff01; 技术提示&#xff03;49说明了如何使用用户名/密码和Servlet安全机制保护WebSocket的安全。 本技术提示将说明如何在WildFly上使用HTTPS / TLS保护WebSocket。 让我们开始吧&#xff01; 创建一个新的密钥库&#xff1a…