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快速入门链接1,groovy快速入门链接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里面写一个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 : ${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: ${para.tos}</td>
<td colspan="5" class="common_4" >Note: ${para.note}</td>
</tr>
<tr>
<td colspan="5" class="common_4" style="font-weight:normal;">DAP: ${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();
}
}
第一次写,如有不足多多谅解,欢迎留言!