You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PrimeFaces DataExporter导出dataTable每行图片到PDF

问题描述

我的XHTML页面里用了dataTable展示行数据,表格包含多列文本和一列图片。目前已经能把所有记录的文本列导出为PDF,但每行的图片没办法导出。我搜了很多帖子找导出每行图片的方法,都没成功。请注意我不需要导出页眉或页脚的单张图片,这类需求可以用p:dataExporter标签的preProcessor属性实现,我已经找到用dataExport标签的PreProcessor导出单张图片的参考示例,也能正常运行,但完全没找到逐行导出图片的指引或示例,求大家帮忙!

技术栈

  • JSF2
  • PrimeFaces 4.0
  • itext-1.1.4
  • JDK1.8
  • GlassFish Server 4

效果说明

我当前的XHTML页面输出里,User Active列是绿勾和红叉图标,我需要把这两个图标也导出到PDF中,目前导出的PDF里该列为空。

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://xmlns.jcp.org/jsf/facelets"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:p="http://primefaces.org/ui">

    <ui:composition template="/templates/common.xhtml">
        <ui:define name="content">
            <h:panelGroup id="formTitle" layout="block">
                <h:outputText value="#{bundle.ListUsersTitle}"></h:outputText>
            </h:panelGroup>
            <h:form styleClass="jsfcrud_list_form">
                <h:panelGroup id="messagePanel" layout="block">
                    <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>
                </h:panelGroup>
                <h:outputText escape="false" value="#{bundle.ListUsersEmpty}" rendered="#{usersController.items.rowCount == 0}"/>
                <h:panelGroup rendered="#{usersController.items.rowCount > 0}">
                    <p:dataTable id="dtUsers" value="#{usersController.items}" var="item" scrollable="true" scrollHeight="500">
                        <p:column sortBy="#{item.id}">
                            <f:facet name="header">
                                <h:outputText value="#{bundle.ListUsersTitle_id}"/>
                            </f:facet>
                           <h:outputText value="#{item.id}" /> 
                        </p:column>
                        <p:column sortBy="#{item.userName}">
                            <f:facet name="header">
                                <h:outputText value="#{bundle.ListUsersTitle_userName}"/>
                            </f:facet>
                           <h:outputText value="#{item.userName}" /> 
                        </p:column>
                        <p:column sortBy="#{item.userPassword}" exportable="false">
                            <f:facet name="header">
                                <h:outputText value="#{bundle.ListUsersTitle_userPassword}"/>
                            </f:facet>
                            <h:outputText value="#{item.userPassword}" />
                        </p:column>
                        <p:column id="userActiveCol" sortBy="#{item.userActive}">
                            <f:facet name="header">
                                <h:outputText value="#{bundle.ListUsersTitle_userActive}"/>
                            </f:facet>
                            <h:graphicImage id="yesId" value="/img/Yes.png" alt="Yes" rendered="#{item.userActive == 'Y'}"/>
                            <h:graphicImage id="noId" value="/img/No.png" alt="No" rendered="#{item.userActive == 'N'}"/>
                        </p:column>
                        <p:column sortBy="#{item.userSource}">
                            <f:facet name="header">
                                <h:outputText value="#{bundle.ListUsersTitle_userSource}"/>
                            </f:facet>
                            <h:outputText value="#{(item.userSource == 'ORGANIZATION')?'Organization':
                                                   (item.userSource == 'VENDOR')?'Vendor':
                                                   (item.userSource == 'VENDORRESOURCE')?'Vendor Resource':
                                                   (item.userSource == 'CUSTOMER')?'Customer':'Not Known'}" />
                        </p:column>
                        <p:column sortBy="#{item.resourceId}">
                            <f:facet name="header">
                                <h:outputText value="#{bundle.ListUsersTitle_resourceId}"/>
                            </f:facet>
                            <h:outputText value="#{item.resourceId}" />
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="#{bundle.ListUsersTitle_resourceName}"/>
                            </f:facet>
                            <h:outputText value="#{usersController.getResourceName(item)}" />
                        </p:column>
                        <p:column headerText="&nbsp;" exportable="false">
                            <h:panelGroup styleClass="formRowAction">
                                <p:commandLink action="#{usersController.prepareView}" value="#{bundle.ListUsersViewLink}"/>
                            </h:panelGroup>
                            <h:panelGroup styleClass="formRowAction">
                                <p:commandLink action="#{usersController.prepareEdit}" value="#{bundle.ListUsersEditLink}"/>
                            </h:panelGroup>
                            <h:panelGroup styleClass="formRowAction">
                                <p:commandLink action="#{usersController.destroy}" 
                                               value="#{bundle.ListUsersDestroyLink}" />
                            </h:panelGroup>
                        </p:column>
                    </p:dataTable>
                </h:panelGroup>
                <br />
                <h:panelGroup styleClass="formBottomActions">
                    <h:panelGroup>
                        <h:commandLink action="#{usersController.prepareCreate}" value="#{bundle.ListUsersCreateLink}"/>
                    </h:panelGroup>
                    <h:panelGroup>
                        <p:commandLink value="#{bundle.ExportPDF}" immediate="true" id="generatePDFId" ajax="false">
                            <p:dataExporter type="pdf" target="dtUsers" fileName="Users"/>
                        </p:commandLink>
                    </h:panelGroup>
                    <h:panelGroup>
                        <h:link outcome="/subMenu" value="#{bundle.SubMenuLink}"/>
                    </h:panelGroup>
                    <h:panelGroup>
                        <h:commandLink action="#{menuHandler.returnToMainMenu}" value="#{bundle.mainMenuLink}"/>
                    </h:panelGroup>
                </h:panelGroup>
            </h:form>
        </ui:define>
    </ui:composition>

</html>

解决方案

PrimeFaces 4.0自带的dataExporter默认只导出文本内容,要实现行内图片导出,需要自定义PDF导出逻辑,核心是重写PDFExporter的单元格处理方法,步骤如下:

  1. 自定义PDF导出器
    继承org.primefaces.component.export.PDFExporter类,重写exportCell方法,判断如果单元格里是h:graphicImage组件,就读取图片文件添加到PDF单元格:
import com.lowagie.text.Image;
import com.lowagie.text.pdf.PdfPCell;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.component.export.PDFExporter;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import java.io.IOException;

public class CustomPDFExporter extends PDFExporter {
    @Override
    protected PdfPCell exportCell(FacesContext context, DataTable table, UIComponent component, String encoding) throws IOException {
        // 识别图片组件
        if(component instanceof javax.faces.component.html.HtmlGraphicImage) {
            String imagePath = (String) component.getAttributes().get("value");
            ServletContext servletContext = (ServletContext) context.getExternalContext().getContext();
            String realPath = servletContext.getRealPath(imagePath);
            Image img = Image.getInstance(realPath);
            // 调整图片大小适配单元格,可根据实际图标尺寸修改
            img.scaleToFit(16, 16);
            PdfPCell cell = new PdfPCell(img, true);
            // 对齐方式和其他单元格统一
            cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
            cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
            return cell;
        }
        // 非图片组件走默认导出逻辑
        return super.exportCell(context, table, component, encoding);
    }
}
  1. 在托管Bean中添加导出方法
    调用自定义导出器生成PDF:
import org.primefaces.component.datatable.DataTable;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;

public class UsersController {
    // 原有方法保留
    public void exportPDF() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "attachment;filename=Users.pdf");
        OutputStream os = response.getOutputStream();
        // 此处formId替换为你页面中h:form组件的实际id
        DataTable table = (DataTable) context.getViewRoot().findComponent("formId:dtUsers");
        CustomPDFExporter exporter = new CustomPDFExporter();
        exporter.export(context, table, table.getColumns(), "Users", false, false, "UTF-8", null, null);
        os.flush();
        os.close();
        context.responseComplete();
    }
}
  1. 修改XHTML导出按钮
    替换原有默认导出组件,调用自定义导出方法:
<h:panelGroup>
    <p:commandLink value="#{bundle.ExportPDF}" immediate="true" id="generatePDFId" ajax="false" action="#{usersController.exportPDF}"/>
</h:panelGroup>

注意事项

  • 如果你的图片是动态生成的非静态资源,需要调整图片读取逻辑,从流或者其他存储位置加载Image对象
  • 上述代码已适配你使用的itext 1.1.4版本,无需修改API
  • 如果出现图片路径找不到的问题,可以打印realPath参数调试路径是否正确

内容的提问来源于stack exchange,提问作者Anupam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 07:15:04