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

primefaces

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;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(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;
    }

    @Override
    public 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;

    @Override
    protected 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 {

    @EJB
    ColumnModelFacade 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 state

        UIComponent table = FacesContext.getCurrentInstance().getViewRoot().findComponent(":customerExportForm:customerTable");

        table.setValueExpression("sortBy", null);



        //update columns

        createDynamicColumns();

    }

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。

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

primefaces

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值