如何使用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=" " 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的单元格处理方法,步骤如下:
- 自定义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); } }
- 在托管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(); } }
- 修改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
相关产品推荐
相关产品推荐

