Export your dataTable to Excel and PDF using Primefaces

Do you need exporting your JSF dataTable to any kind of format such as Excel, PDF, CSV, XML ? We have updated this tutorial to Primefaces 10 to do it in a minute!

In order to export your dataTable, you can use the DataExporter UICommand which is part of the Primefaces suite. Using it is pretty simple. The required libraries to run this example are:

  • Primefaces library
  • Apache POI library (dependency)
  • iText library  (dependency)

The recommended way to configure your project for a Jakarta EE server (such as WildFly) requires the following dependencies in your pom.xml:

<dependencies>
    <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-api</artifactId>
        <version>8.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>${primefaces.version}</version>
    </dependency>

    <dependency>
        <groupId>com.lowagie</groupId>
        <artifactId>itext</artifactId>
        <version>2.1.7</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.0.0</version>
    </dependency>
</dependencies>

The PrimeFaces component required to export your dataTable is called DataExporter and it is nested in a UICommand component such as commandButton or commandLink. See the following example:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">

<h:head>
</h:head>

<h:body>
    <h:form id="jsfexample">
        <p:panelGrid columns="2">
            <f:facet name="header">  
                Basic PanelGrid  
           </f:facet>
            <h:outputLabel for="key" value="Enter Name" />
            <p:inputText id="key" value="#{manager.name}" />

            <h:outputLabel for="value" value="Enter Surname" />
            <p:inputText id="value" value="#{manager.surname}" />

            <h:outputLabel for="age" value="Enter Age" />
            <p:inputText id="age" value="#{manager.age}" />

            <h:outputLabel for="city" value="Enter City" />
            <p:inputText id="city" value="#{manager.city}" />
            <p:commandButton action="#{manager.save}" update="mydata"
                value="Save" icon="ui-icon-check" style="margin:0" />
            <p:commandButton action="#{manager.clear}" update="mydata"
                value="Delete" icon="ui-icon-cancel" style="margin:0" />

            <h:messages />

        </p:panelGrid>
        <br />
        <p:dataTable value="#{manager.cacheList}" var="item" id="mydata">
            <p:column>
                <f:facet name="header">Name</f:facet>
                <h:outputText value="#{item.name}" />
            </p:column>
            <p:column>
                <f:facet name="header">Surname</f:facet>
                <h:outputText value="#{item.surname}" />
            </p:column>
            <p:column>
                <f:facet name="header">Age</f:facet>
                <h:outputText value="#{item.age}" />
            </p:column>
            <p:column>
                <f:facet name="header">City</f:facet>
                <h:outputText value="#{item.city}" />
            </p:column>
        </p:dataTable>
        <p:panel header="Export All Data">
            <h:commandLink>
                <p:graphicImage value="/icons/excel.jpg" />
                <p:dataExporter type="xls" postProcessor="#{manager.postProcessXLS}"
                    target="mydata" fileName="myexcel" />
            </h:commandLink>
            <h:commandLink>
                <p:graphicImage value="/icons/pdf.png" />
                <p:dataExporter type="pdf" target="mydata" fileName="mypdf" />
            </h:commandLink>
        </p:panel>

    </h:form>
</h:body>
</html>

As you can see this page contains:

  • a form for instering data
  • a datatable with id=”mydata”
  • a panel used to export data in Excel or PDF

The <p:dataExporter> specifies the type of export with the “type” attribute. You can opt between “xls“,”pdf,”csv” and “xml“. Next, you need to select the dataTable with the “target” attribute and the resulting filename with the “fileName” attribute. (In this tutorial we will show just Excel and PDF export, however using csv and xml is trivial, just add the required type attribute to the dataExporter)

Additionally an Excel, PDF dataExporter can use the preProcessor or postProcessor to add some pre-processing or post-processing functionalities to your document. This can be used to add custom styles to your document or also to modify the content as well. For example here is the JSF bean which contains the Excel postProcessor method postProcessXLS which does some uppercase and styling to your excel:

package com.mastertheboss.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Locale;

import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;

import com.mastertheboss.model.Person;

@Named(value = "manager")
@ViewScoped
public class PropertyManager implements Serializable {

    private String name;
    private String surname;
    private int age;
    private String city;

    ArrayList<Person> cacheList = new ArrayList();

    public void save() {
        Person p = new Person(name, surname, age, city);
        cacheList.add(p);
    }

    public void clear() {
        cacheList.clear();
    }

    public void postProcessXLS(Object document) {

        HSSFWorkbook wb = (HSSFWorkbook) document;
        HSSFSheet sheet = wb.getSheetAt(0);
        CellStyle style = wb.createCellStyle();
        style.setFillBackgroundColor(IndexedColors.AQUA.getIndex());

        for (Row row : sheet) {
            for (Cell cell : row) {

                switch (cell.getCellType()) {

                case STRING:
                    cell.setCellValue(cell.getStringCellValue().toUpperCase());
                    cell.setCellStyle(style);
                    break;

                }

            }
        }
    }

    // Getters/Setters omitted for brevity
}

Within the postProcessXLS we are iterating over the list of Rows and Cells of the Spreadsheet. then, we are checking the Cell type to apply an Uppercase if the Cell contains a String

Here’s the application in action:

Exporting the dataTable in CSV or XML

It is also possible to export your dataTable in other standard formats such as CSV or XML. It is only matter of changing the type attribute. For example, in CSV format:

<h:commandLink>
	<p:commandButton value="Export as CSV" ajax="false" >
	<p:dataExporter type="csv" target="mydata" fileName="mycsv.csv" pageOnly="true" />
</h:commandLink>

This is how to export the dataTable in XML format:

<h:commandLink>
	<p:commandButton value="Export as XML" ajax="false" >
	<p:dataExporter type="xml" target="mydata" fileName="mydata.xml" pageOnly="true" />
</h:commandLink>

Exporting only the current page

By default dataExporter works on whole dataset, if you’d like export only the data displayed on current page (as we did in our example), set the pageOnly attribute to true.

<p:dataExporter type="xml" target="mydata" fileName="mydata.xml" pageOnly="true" />

Installing POI and iText as modules on WildFly

If you plan to use POI and iText across several applications of yours, then why not installing them as a module with WildFly ? First download the JAR files for both libraries.

Then, you can install them on WildFly as a module by running the following CLI command:

[standalone@localhost:9990 /] module add --name=org.apache.poi --dependencies=javax.api,org.apache.commons.logging --resources=poi-5.0.0.jar
[standalone@localhost:9990 /] module add --name=com.lowagie.itext --resources=itext-2.1.7.jar

This is the module structure for Apache POI:

+---org
     +---apache
         +-----poi
              +-----main
                    module.xml
                    poi-3.17.jar

Within it, there’s the following module.xml:

<module xmlns="urn:jboss:module:1.1" name="org.apache.poi">
    <properties>
        <property name="jboss.api" value="private"/>
    </properties>
    <resources>
        <resource-root path="poi-3.17.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="org.apache.commons.logging"/>
    </dependencies>
</module>

On the other hand, this is the module path for iText:

+---com
      +----lowagie
           +----itext
                +-----main
                      module.xml
                      itext-2.1.7.jar

And the corresponding module.xml

<module xmlns="urn:jboss:module:1.1" name="com.lowagie.itext">

    <properties>
        <property name="jboss.api" value="private"/>
    </properties>

     <resources>
        <resource-root path="itext-2.1.7.jar"/>
    </resources>
    <dependencies>
    </dependencies>

</module>

Fine, now the last thing to do is setting the application dependencies into the META-INF/MANIFEST.MF file:

Manifest-Version: 1.0
Dependencies: org.apache.poi com.lowagie.itext export

Great. Now your WildFly is able to use iText and POI libraries as a module.

 Last thing to note: the current release of Primefaces libraries refers to an older release of iText. If you try to install the latest iText distribution you will end up to the following error: java.lang.NoClassDefFoundError: com/lowagie/text/
This is due to the fact that in the recent iText release the package com/lowagie/text has been renamed as com/itextpdf/text. So until this is fixed use the suggested iText release (2.1.7) or at least verify the package structure.

You can find the code from this PrimeFaces Exporter Demo here. Enjoy it !