如何动态生成pdf文件?

pdfService系统

一、 背景

在许多开发需求中都有动态生成pdf文件的需求,例如根据已有的json字符串渲染到一个表格中,然后生成对应的PDF文档,以往的解决方法是调用许多个接口生产pdf文件,其过程复杂和开发时间过长,不利于实际开发的情况。在此情况下需要一个系统来加快完成生成pdf文件的过程,因此pdfService应运而生。

二、PdfService介绍

(一)结构介绍

pdfService是一个SpringBoot项目主要是由service,template和pdfGroovy构成。

(二)功能介绍:

1、IText:iText官网链接

iText是著名的开放源码的站点sourceforge一个项目,是用于生成PDF文档的一个java类库。通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件

2、groovy:groovy官网链接

groovy快速入门链接1groovy快速入门链接2;
Groovy是一种基于JVM(Java虚拟机)的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy 代码能够与 Java 代码很好地结合,也能用于扩展现有代码。由于其运行在 JVM 上的特性,Groovy也可以使用其他非Java语言编写的库。

3、pdfService:

其核心运用groovy描绘基本的html,调用iText的java类库生成PDF文档。
pdfService的功能流程是先读取json数据渲染到groovy的html上,然后进入service层调用iText的java类库解析html文件生成PDF文档,最后返回pdf文档的byte文件,其流程图如下:
pdfService流程图

(三)例子:

现在需要在pdfService里面写一个proform.pdf文档功能,内容要求如下:

1、要有表头,表尾,每页的头部和尾部要有页码的信息。
2、能动态渲染数据,能够插入图片显示。

首先创建四个文件 proforma.json,proforma.groovy,ProformaPdfTemplate.java,PdfGenerator.java

3.1、proforma.json的功能说明:主要是需要渲染的json数据,内容如下:
//以下为渲染到proform.pdf的json数据data
{
    "data":{
        "proformaInvoicNo":"3201900351",
        "name1":"MARIA CHIARA ROSSETTO",
        "name2":"NAYA ALDIAS",
        "shipper":"BULGARI IRELAND  LTD",
        "consignee":"Bulgari Canada Inc",
        "address1":"Macken House Mayor Upper Dublin1-Ireland DUBLIN DUBLIN 1 +3538750533",
        "address2":"3401 Dufferin Street Unit 163A Toronto, Ontari M6A2T TRONTO M6A2T9 0014167893261",
        "vatNumber1":"IE96787331",
        "vatNumber2":"IE96787331",
        "phone1":"07918316800",
        "phone2":"955288",
        "pickupPalace":"ORIGIN UE",
        "forwarder":"Omlog",
        "deliverTo":"BULGARI STORE VANCOUVER(8959) 737 DUNSMUIR ST. VANCOUVER V7Y1E4 00160046813121",
        "referent":"MARIA CHIARA ROSSETTO",
        "campaign":"HL TRAYS 2019",
        "country":"CANADA",
        "productArryJson":[{"quantity":"2.00","description":"HIGHLIGHT TRAY HS CODE 94038900","poNumber":"1610131298","unitValue":"50.00","totalValue":"100.00"},{"quantity":"1.00","description":"SLG TRAY HS CODE 94038900","poNumber":"1610131298","unitValue":"310.00","totalValue":"310.00"},{"quantity":"3.00","description":"EST - Outside Fabric: 75%WO 25%PA  - FOD - Lining: 67%AC 33%PL","poNumber":"1610131298","unitValue":"200.00","totalValue":"600.00"},{"quantity":"4.00","description":"EST - Outside Fabric: 75%WO 25%PA  - FOD - Lining: 67%AC 33%PL","poNumber":"1610131298","unitValue":"100.00","totalValue":"400.00"}],
        "totalValueAmount":"41410.00",
        "tos":"CHECKED",
        "note":"passed",
        "drp":"100%cartoon",
        "extPckg":"BOX",
        "totPcs":"1.000",
        "totCbm":"0.027",
        "totGrossWeight":"6.000",
        "trackingNumber":"1Z0X7W490496235930",
        "dims":"30.0000×30.000×30.000(LxWxH)",
        "grossWeight":"6.000",
        "placeAndDate":"DUBLIN,11/07/2019"
    }   
}
3.2 proforma.groovy功能说明:

groovy内的html内容用html=““” htmlContent “”“来包含,html的内容是由style,body和body内的table组成如图所示内容如下:
其中groovy内的html内容用html=""" htmlContent"""来包含,html的内容是由style,body和body内的table组成,传入的json数据直接渲染至html用${para.XXX}html的表头在table内用< thead> </ thead>
表尾用 <tfoot> </foot >包含,并且在table标签的style属性加上repeat-header:yes;repeat-footer:yes;后面的iText解析html时会根据此样式生成PDF文档时每页显示表头和表尾的信息

import net.sf.json.JSONObject
productArryJson=para.productArryJson

productStr=""""""
//根据productArryJson的大小和内容对象,动态循环显示每一行的数据。
if(productArryJson.size()>0) { 
    for (int i = 0; i < productArryJson.size(); i++) {      
        JSONObject product = (JSONObject) productArryJson.get(i);
            productStr=productStr+"""
            <tr> 
            <td colspan="1" class="common_5" style="font-size:12px;">"""+product.getString("quantity")+"""</td>
            <td colspan="6" class="common_5" style="font-size:12px;">"""+product.getString("description")+"""</td>
            <td colspan="1" class="common_5" style="font-size:12px;">"""+product.getString("poNumber")+"""</td>
            <td colspan="1" class="common_5" style="font-size:12px;">€"""+product.getString("unitValue")+"""</td>
            <td colspan="1" class="common_5" style="font-size:12px;">€"""+product.getString("totalValue")+"""</td>
            </tr>
            <tr>
            <td colspan="10"  class="common_2" style="height:10px">1.1</td>
           </tr>
            """
    }
}

html = """

<!--html的样式style设计 -->
<style type="text/css">
    .common_1{
        border:1px solid black;
        color:white;
        height:20px; 
        font-size:13px;
        text-align:center;
        background:black;
        font-weight:bold;
    }
    .common_2{
        text-align:center;
        color:white; 
    }
    .common_3{
        border:1px solid black;
        color:black;
        height:20px;  
        text-align:center;
        background:white;
    }    
    .common_4{
        border:1px solid black;
        color:white;
        text-align:center;
        background:black;
        height:20px;
        font-size:15px;
        font-weight:bold;
    } 
    .common_5{
        border:1px solid white;
        color:black;
        text-align:center;
        background:white;
        height:20px;
        font-size:15px;
    }
    .common_6{
        text-align:center;
        color:#999999;
    }       
</style>
<body> 
		<!-- 设计pdf表头,表尾时,需要表的style声明repeat-header:yes;repeat-footer:yes;多张显示会自动循环表头表位内容 --> 
       <table cellspacing="0" valign="center" style="repeat-header:yes;repeat-footer:yes;font-size:10px;width:700px;border:1px solid white">
       		<!--用 <thead></thread>声明表头内容-->      
            <thead> 
               <tr>
               <!--imgPath传入的参数为本地的绝对路径比如C:/img/logo.jpg -->                                                
                   <th colspan="10" ><img src="${para.imgPath}"   style="width:700px;height:60px" /></th>
               </tr>
               <tr>                                                
                   <th colspan="10" style="height:15px"></th>
               </tr>
            </thead>
              <tbody>
                  <tr>
                    <td colspan="5" class="common_1" style="height:30px;font-size:20px;text-align:right;" >Proforma Invoice N°</td>
                    <td colspan="5" class="common_1" style="height:30px;font-size:20px;text-align:center;" >${para.proformaInvoicNo}</td>
                  </tr>
                  <tr>
                    <td class="common_2">1.1</td>
                    <td class="common_2">1.2</td>
                    <td class="common_2">1.3</td>
                    <td class="common_2">1.4</td>
                    <td class="common_2">1.5</td>
                    <td class="common_2">1.6</td>
                    <td class="common_2">1.7</td>
                    <td class="common_2">1.8</td>
                    <td class="common_2">1.9</td>
                    <td class="common_2">1.10</td>
                  </tr>
                  <tr>
                    <td class="common_1" colspan="2" style="background:#222222;"><strong>Name</strong></td>
                    <td class="common_3" colspan="3" >${para.name1}</td>
                    <td class="common_1" colspan="2" style="background:#222222;">Name</td>
                    <td class="common_3" colspan="3">${para.name2}</td>
                  </tr>
                  <tr>
                    <td class="common_1" colspan="2" style="background:#222222;">Shipper</td>
                    <td class="common_3" colspan="3">${para.shipper}</td>
                    <td class="common_1" colspan="2" style="background:#222222;">Consignee</td>
                    <td class="common_3" colspan="3">${para.consignee}</td>
                  </tr>
                  <tr>
                    <td colspan="2" class="common_1" rowspan="2" style="height:40px;background:#222222;" >Address</td>
                    <td class="common_3" colspan="3" rowspan="2">${para.address1}</td>
                    <td colspan="2" class="common_1" rowspan="2" style="height:40px;background:#222222;">Address</td>
                    <td class="common_3" colspan="3" rowspan="2">${para.address2}</td>
                  </tr>
                  <tr>
                  </tr>
                  <tr>
                    <td class="common_1" colspan="2" style="background:#222222;">Var Number</td>
                    <td class="common_3" colspan="3">${para.vatNumber1}</td>
                    <td class="common_1" colspan="2" style="background:#222222;">Var Number</td>
                    <td class="common_3" colspan="3">${para.vatNumber2}</td>
                  </tr>
                  <tr>
                    <td class="common_1" colspan="2" style="background:#222222;">Phone</td>
                    <td class="common_3" colspan="3">${para.phone1}</td>
                    <td class="common_1" colspan="2" style="background:#222222;">Phone</td>
                    <td class="common_3" colspan="3">${para.phone2}</td>
                  </tr>
                   <tr>
                    <td class="common_1" colspan="2" style="background:#222222;">Pick-up Place</td>
                    <td class="common_3" colspan="3">${para.pickupPalace}</td>
                    <td class="common_1" colspan="2" style="background:#222222;">Forwarder</td>
                    <td class="common_3" colspan="3">${para.forwarder}</td>
                  </tr>
                  <tr>
                    <td class="common_2">1.1</td>
                    <td class="common_2">1.2</td>
                    <td class="common_2">1.3</td>
                    <td class="common_2">1.4</td>
                    <td class="common_2">1.5</td>
                    <td class="common_2">1.6</td>
                    <td class="common_2">1.7</td>
                    <td class="common_2">1.8</td>
                    <td class="common_2">1.9</td>
                    <td class="common_2">1.10</td>
                  </tr>
                    <tr>
                    <td colspan="4"></td>
                    <td colspan="6">Deliver To :&nbsp;&nbsp;${para.deliverTo}</td>
                  </tr>
                   <tr>
                    <td colspan="10"  class="common_2" style="height:20px">1.1</td>
                  </tr>
                  <tr>
                    <td colspan="4" class="common_4"  >Referent:</td>
                    <td colspan="3" class="common_4"  >Campaign:</td>
                    <td colspan="3" class="common_4"  >Country:</td>
                  </tr>
                   <tr>
                    <td colspan="4" class="common_4" style="font-weight:normal;"  >${para.referent}</td>
                    <td colspan="3" class="common_4" style="font-weight:normal;" >${para.campaign}</td>
                    <td colspan="3" class="common_4" style="font-weight:normal;">${para.country}</td>
                  </tr>
                  <tr>
                    <td colspan="10"  class="common_2" style="height:20px">1.1</td>
                  </tr>
                   <tr>                                
                    <td  colspan="1" class="common_4" style="border:1px solid white;font-size:12px;">Quantity</td>
                    <td  colspan="6" class="common_4" style="border:1px solid white;font-size:12px;">Descripion</td>
                    <td  colspan="1" class="common_4" style="border:1px solid white;font-size:12px;">PO Number</td>
                    <td  colspan="1" class="common_4" style="border:1px solid white;font-size:12px;">Unit Value</td>
                    <td  colspan="1" class="common_4" style="border:1px solid white;font-size:12px;">Total Value</td>
                  </tr>
                  <tr>
                    <td class="common_2" colspan="10" style="height:2px;"></td>
                  </tr>
                  <tr>
                    <td class="common_2" colspan="10" style="height:20px;background-color:#7F7F7F;" >Dos stores()</td>
                  </tr>
                  <tr>
                    <td class="common_2" colspan="10" style="height:2px;"></td>
                  </tr>
                  """+productStr+"""    
                  
                   <tr>                                
                    <td  colspan="8" class="common_4" style="border:1px solid white;font-weight:normal;">Value for custom purpose only</td>
                    <td  colspan="1" class="common_4" style="border:1px solid white;font-size:12px;">Total Value</td>
                    <td  colspan="1" class="common_4" style="border:1px solid white;font-size:12px;">€${para.totalValueAmount}</td>
                  </tr>
                  <tr>
                    <td colspan="10"  class="common_2" style="height:20px">1.1</td>
                  </tr>
                   <tr>
                    <td colspan="5" class="common_4"  >Tos:&nbsp;&nbsp;${para.tos}</td>
                    <td colspan="5" class="common_4"  >Note:&nbsp;&nbsp;${para.note}</td>
                  </tr>
                  <tr>
                    <td colspan="5" class="common_4"  style="font-weight:normal;">DAP:&nbsp;&nbsp;${para.drp}</td>
                    <td colspan="5" class="common_4"  ></td>
                  </tr>
                   <tr>
                    <td colspan="10"  class="common_2" style="height:20px">1.1</td>
                  </tr>
                  <tr>
                    <td colspan="10" style="font-size:12px">The exporter of the products convered by this document declares that,except where otherwise clearly indicted these products are of Italian<br></br>
                    preferential origin.<br></br>
                    Besides, the exporter declared that all information in this invoice is true and correct.<br></br>
                    La merce non è vincolata a licenze di esportazione e quindi:<br></br>
                    - Regolamento UE n. 101/2012, relativo alla protezione di specie della flora e fauna selvatiche mediante controllo del loro commercio<br></br>
                    (CONVENZIONE DI WASHINGTON - CITES) (codice Y900);<br></br>
                    - Non rientra nell'elenco di beni come da Regolamento CEE n. 1 16/2009 relativo all'esportazione dei beni culturali (codice Y903-Y905);<br></br>
                    - Non rientra nel campo di applicazione del REG( UE ) nr 1332/2013 (g.u. UE L.335 )( codice Y935)<br></br>
                    - Non rientra nell'elenco dei beni come da Regolamento (UE) n.388/2012 del Parlamento Europeo e del Consiglio, del 19 aprile 2012, che <br></br>
                    modifica Regolamento (UE) n.428/2009 del Consiglio, del 5 maggio 2009, che istituisce un regime comunitario di controllo delle<br></br>
                    exortazioni,del trasferimento.dell'intermediazione e del transito di prodotti a duplice uso (Dual Use)(Y901)<br></br></td>
                  </tr>
                   <tr>
                    <td colspan="10"  class="common_2" style="height:40px">1.1</td>
                  </tr>
                  <tr>
                    <td colspan="2" class="common_4"  >EXT:PCKG</td>
                    <td colspan="2" class="common_4"  >TOT PCS</td>
                    <td colspan="2" class="common_4"  >TOT CBM</td>
                    <td colspan="4" class="common_4"  >TOT GROSS WEIGHT</td>
                  </tr>
                  <tr>
                    <td colspan="2" class="common_4"  style="font-weight:normal;">${para.extPckg}</td>
                    <td colspan="2" class="common_4"  style="font-weight:normal;">${para.totPcs}</td>
                    <td colspan="2" class="common_4"  style="font-weight:normal;">${para.totCbm}</td>
                    <td colspan="4" class="common_4"  style="font-weight:normal;">${para.totGrossWeight}</td>
                  </tr>
                  <tr>
                    <td colspan="10"  class="common_2" style="height:20px">1.1</td>
                  </tr>
                   <tr>
                    <td colspan="3" class="common_4">TRACKING NUMBER</td>
                    <td colspan="4" class="common_4">DIMS(cm)</td>
                    <td colspan="3" class="common_4">GROS WEIGHT</td>
                  </tr>
                    <tr>
                    <td colspan="3" class="common_4" style="font-weight:normal;">${para.trackingNumber}</td>
                    <td colspan="4" class="common_4" style="font-weight:normal;">${para.dims}</td>
                    <td colspan="3" class="common_4" style="font-weight:normal;">${para.grossWeight}</td>
                  </tr>
                  <tr>
                    <td colspan="10"  class="common_2" style="height:750px;">1.1</td>
                  </tr>
                  <tr><td colspan="10" style="text-align:left;font-size:15px">${para.placeAndDate}</td></tr>
                  <tr><td colspan="10" style="text-align:right;font-size:15px">Signature </td></tr>
                  <tr> <td colspan="10"  class="common_2" style="height:10px">1.1</td></tr>
                  <tr><td colspan="10" style="text-align:right;">${para.proformaInvoicNo}</td></tr>
             </tbody>
             <!--表位内容用 <tfoot></tfoot>包含-->      
             <tfoot>
                  <tr>
                    <td colspan="10"  class="common_2" style="height:40px;"></td>
                  </tr>
                  <tr><td colspan="10"  class="common_6"><strong>BULGARIIRELAND</strong> Limited- Incorporated in lreland under Compan Reg. No 454082</td></tr>
                  <tr><td colspan="10"  class="common_2" style="height:5px">1.1</td></tr> 
                  <tr><td colspan="10" class="common_6">Business/CorrespondenceAddress-MackenHouse,Castleforbes Square,Upper Mayor Street Dublin 1</td> </tr>
                  <tr><td colspan="10"  class="common_2" style="height:5px">1.1</td></tr> 
                  <tr><td colspan="10" class="common_6">Registered Office- 70 Sir John Rogerson's Quay,Dublin 2</td></tr>
                  <tr><td colspan="10"  class="common_2" style="height:5px">1.1</td></tr> 
                  <tr><td colspan="10" class="common_6">VAT Reg. No: IE 96787331</td> </tr>
            </tfoot>
        </table>
</body>
"""

3.3 ProformaPdfTemplate.java功能说明

继承了Itext的PdfPageEventHelper,主要可以初始化字体样式,设置页码的显示等。内容如下:

package com.om3000.v2.standalone.ws.pdfService.template;

import java.io.IOException;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;

public class ProformaPdfTemplate extends PdfPageEventHelper {
	//页面总数 totalPageTpl
    private PdfTemplate totalPageTpl;
	//字体样式
    private BaseFont bf = null;
	//页脚
    private Font fontDetail = null;
	//页头
    private Font fontHeader = null;
	//字体大小
    private int footFontSize = 8;
    
	//开启html文档读取并且写入pdf
	
    public void onOpenDocument(PdfWriter writer, Document document) {
        totalPageTpl = writer.getDirectContent().createTemplate(50, 50);
    }

    public void onEndPage(PdfWriter writer, Document document) {
        this.initFont();
        this.addPageInfo(writer, document);
    }
	//初始化字体样式
    private void initFont() {
        try {
            if (bf == null) {
                bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            }
            if (fontHeader == null) {
                BaseColor bwlBLUE = new BaseColor(104, 130, 194);
                fontHeader = new Font(bf, 14, Font.BOLD, bwlBLUE);
            }
            if (fontDetail == null) {
                fontDetail = new Font(bf, footFontSize, Font.NORMAL);
            }
        } catch (DocumentException | IOException e) {
            e.printStackTrace();
        }
    }
	//页头和页尾增加页码信息
    private void addPageInfo(PdfWriter writer, Document document) {
        int pageS = writer.getPageNumber();
        String foot1 = pageS + "  page" + "  /";
        Phrase footer = new Phrase(foot1, fontDetail);
        PdfContentByte cb = writer.getDirectContent();
        //页脚的页码信息位置设置
        ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, document.right() - 300, document.bottom() - 30, 0);
        cb.addTemplate(totalPageTpl, document.right() - 285, document.bottom() - 30);
        String head1 = "Page " + pageS + " of";
        Phrase header = new Phrase(head1, fontDetail);
        //页头的页码信息位置设置
        ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, header, document.right() - 40, document.bottom() + 750, 0);
        cb.addTemplate(totalPageTpl, document.right() - 25, document.bottom() + 750);
    }
	//关闭html文档
    public void onCloseDocument(PdfWriter writer, Document document) {
        totalPageTpl.beginText();
        totalPageTpl.setFontAndSize(bf, footFontSize);
        //设置页码的总页数
        String foot2 = " " + (writer.getPageNumber() - 1);
        totalPageTpl.showText(foot2);
        totalPageTpl.endText();
        totalPageTpl.closePath();
    }
}

3.4 PdfGenerator.java功能说明

一个生成pdf文档公共调用的类,传入groovy的html,需要渲染的数据data和设置的模板template,内容如下

package com.om3000.v2.standalone.ws.pdfService.generator;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Map;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.RectangleReadOnly;
import com.itextpdf.text.pdf.PdfPageEvent;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorker;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.css.StyleAttrCSSResolver;
import com.itextpdf.tool.xml.html.CssAppliers;
import com.itextpdf.tool.xml.html.CssAppliersImpl;
import com.itextpdf.tool.xml.html.TagProcessorFactory;
import com.itextpdf.tool.xml.html.Tags;
import com.itextpdf.tool.xml.parser.XMLParser;
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
import com.om3000.v2.standalone.ws.common.util.Utils;

public class PdfGenerator {
	//需要渲染的json数据data
    private Map<String, Object> data;
	//pdf的模板
    private PdfPageEvent template;
	//最后生成的pdf二进制输出流
    private ByteArrayOutputStream outputOs = new ByteArrayOutputStream();
	//读取groovy文件的html内容
    private String gvContent;

    private byte[] result = null;

    public PdfGenerator(String gvContent, Map<String, Object> data, PdfPageEvent template) {
        this.gvContent = gvContent;
        this.data = data;
        this.template = template;
    }

    public boolean gen() {
    	//将 groovy的html内容和json数据data动态渲染结合成html
        String html = Utils.compileGroovyToHtml(gvContent, data);
        outputOs = new ByteArrayOutputStream();
        try {
            createPdf(outputOs, html, template);
        } catch (Exception e) {
            e.printStackTrace();
        }
        result = outputOs.toByteArray();
        if (result.length > 0) {
            return true;
        } else {
            return false;
        }
    }
	//根据htmlStr内容和模板template内容,生成pdf文件文档的OutputStream
    public void createPdf(OutputStream os, String htmlStr, PdfPageEvent template) throws Exception {
        Rectangle pageSize = new RectangleReadOnly(625, 842);
        Document document = new Document(pageSize, 50, 30, 30, 70);
        PdfWriter writer = PdfWriter.getInstance(document, os);
        writer.setPageEvent(template);
        document.open();
        CSSResolver cssResolver = new StyleAttrCSSResolver();
        // HTML
        XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider() {

            @Override
            public Font getFont(String fontName, String encoding, float size, int style) {
                return super.getFont(fontName, encoding, size, style);
            }
        };
        CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
        HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
        TagProcessorFactory factory = Tags.getHtmlTagProcessorFactory();
        htmlContext.setTagFactory(factory);
        // Pipelines
        PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
        HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
        CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);
        // XML Workerdfesdsdadsdasdadasda
        XMLWorker worker = new XMLWorker(css, true);
        XMLParser p = new XMLParser(worker);
        p.parse(new ByteArrayInputStream(htmlStr.getBytes()), Charset.forName("UTF-8"));
        // step 5
        document.close();
    }

    public byte[] toByteResult() {
        if (result != null) {
            return result;
        }
        return null;
    }

    public String toBase64Result() {
        if (result != null) {
            return Utils.toBase64String(result);
        }
        return null;
    }
}

最后只需要一个测试类,即可生成你想要的pdf文件:

package com.om3000.v2.standalone.ws.pdfService.service;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.junit.Test;

import com.itextpdf.text.pdf.PdfPageEvent;
import com.om3000.v2.standalone.ws.pdfService.generator.PdfGenerator;
import com.om3000.v2.standalone.ws.pdfService.template.ProformaPdfTemplate;

import net.sf.json.JSONObject;

public class pdfGenTest {
	//groovy文件位置
    private static final String proformaGroovyPath = "src/main/resources/pdfGroovy/proforma.groovy";
	//pdfJson数据data文件位置
    private static final String proformaJsonPath = "src/test/resources/pdfJson/proforma.json";
	//需要引入的图片位置
    private static final String imagLogoPath = "src/main/resources/img/logo.jpg";
	
    @SuppressWarnings("unchecked")
    @Test
    public void genProformaPdf() throws IOException {
    	//1、读取json文件内容引入pdf模板、相关参数设置公共类PdfGenerator 
        File file = new File(proformaJsonPath);
        String str = FileUtils.readFileToString(file);
        JSONObject jsonObject = JSONObject.fromObject(str);
        //2、设置json的data数据
        JSONObject data = (JSONObject) jsonObject.get("data");
        data.put("imgPath", imagLogoPath);
        //3、读取groovy文件内容,并且动态渲染数据
        String gvContent = FileUtils.readFileToString(new File(proformaGroovyPath));
        //4、引用pdf的模板
        PdfPageEvent template = new ProformaPdfTemplate();
        //5、进入生成pdf的公共类PdfGenerator ,传入groovy内容,json数据data,pdf模板,三个参数
        PdfGenerator g = new PdfGenerator(gvContent, data, template);
        assertEquals(true, g.gen());
        //6、将生成的pdf获取其内容的二进制,并写入生成到本地c:\\pdf\\proforma.pdf
        byte[] bb = g.toByteResult();
        FileOutputStream os = new FileOutputStream(new File("c:\\pdf\\proforma.pdf"));
        os.write(bb);
        os.close();
    }
}

第一次写,如有不足多多谅解,欢迎留言!

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值