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.productArryJsonproductStr=""""""
//根据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 {//页面总数 totalPageTplprivate PdfTemplate totalPageTpl;//字体样式private BaseFont bf = null;//页脚private Font fontDetail = null;//页头private Font fontHeader = null;//字体大小private int footFontSize = 8;//开启html文档读取并且写入pdfpublic 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数据dataprivate 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动态渲染结合成htmlString 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文件文档的OutputStreampublic 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();// HTMLXMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider() {@Overridepublic 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);// PipelinesPdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);// XML WorkerdfesdsdadsdasdadasdaXMLWorker worker = new XMLWorker(css, true);XMLParser p = new XMLParser(worker);p.parse(new ByteArrayInputStream(htmlStr.getBytes()), Charset.forName("UTF-8"));// step 5document.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")@Testpublic void genProformaPdf() throws IOException {//1、读取json文件内容引入pdf模板、相关参数设置公共类PdfGeneratorFile 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.pdfbyte[] bb = g.toByteResult();FileOutputStream os = new FileOutputStream(new File("c:\\pdf\\proforma.pdf"));os.write(bb);os.close();}
}

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

如何动态生成pdf文件?相关推荐

  1. java在linux生成pdf文件,从 Java 应用程序动态生成 PDF 文件

    简介: 如果您的应用程序需要动态生成 PDF 文档,那么您需要 iText 库.开源的 iText 库使得 PDF 的创建变得轻松易行.本文介绍了 iText 并提供了一个使用它从 Java 技术应用 ...

  2. java动态生成pdf文件的方法

    java动态生成pdf文件 文章目录 java动态生成pdf文件 前言 一.生成pdf模板 二.使用步骤 1.使用jar包 2.pdf实现方法 总结 前言 java开发过程中难免会遇到生成文件的需求, ...

  3. Java读取pdf模板,并动态生成pdf文件,如动态生成准考证

    Java读取pdf模板,并动态生成pdf文件,如动态生成准考证 ​ 前几天遇到了一个生成准考证的需求,并提供用户下载,然后百度了一圈还是觉得使用itextpdf这个框架好用点.但是还需要找到一个能创建 ...

  4. java使用world模板动态生成PDF文件

    根据项目需求,需要用到一个功能,根据页面参数需要动态的生成一个world,并将world生成两份PDF文件,一份正式文件,一份临时的电子文件(带有二维码,扫描可以下载正式文件的电子版本).同时上传到文 ...

  5. java设置pdf不可编辑_Java动态生成pdf文件(使用itext编辑pdf)

    一.创建pdf模板 使用PDFelement制作pdf模板(数据域的名称对应后面插入的key) 二.导入maven依赖 com.itextpdf itextpdf 5.5.13 com.itextpd ...

  6. Java动态生成pdf文件(用于实时生成电子证书)

    1.首先,新建一个word文档,内容如下,另存为pdf格式,我的命名:mytest.pdf. 2.用Adobe Acrobat Pro 打开刚刚制作的pdf文件.如下图: 3.点击创建–>PDF ...

  7. java maven 读写pdf_Java动态生成pdf文件(使用itext编辑pdf)

    一.创建pdf模板 使用PDFelement制作pdf模板(数据域的名称对应后面插入的key) 二.导入maven依赖 com.itextpdf itextpdf 5.5.13 com.itextpd ...

  8. .NET动态生成PDF文件(利用iTextSharp)

    1.前台页面上: Code<div><asp:TextBox ID="TextBox1"runat="server"></asp: ...

  9. java动态生成pdf文件(使用itext编辑pdf)

最新文章

  1. [转载] 30分钟泛型教程
  2. Nginx中gzip_static使用测试
  3. linux多线程学习设置线程调度权限
  4. 2013_chengdu_visit
  5. Magento 获取系统设置 How to get data from Magento System Configuration
  6. 360 支持linux版本下载地址,360安全浏览器国产稳定版本发布,提供deb软件包下载,附介绍...
  7. torch中loss.bacword的理解
  8. STM32——库函数版——数码管动态显示程序
  9. 成为一名Java高级工程师需要掌握哪些技能
  10. VS2010SP1中文版安装问题
  11. Linux系统Ubuntu vim安装plugin
  12. 微信模拟地理位置_微信伪装地理位置是什么个原理
  13. wps2016热点永久关闭
  14. js根据身份证获取年龄
  15. python爬虫构建国外代理池_建立爬虫代理ip池
  16. STM32涉及到的汇编基础知识
  17. 安全帽图像识别python_基于opencv的安全帽佩戴检测
  18. 各大互联网大厂年终奖一览表,又是别人家的公司!
  19. CSS3线性渐变与径向渐变
  20. Redis使用setnx实现分布式锁及其问题、优化

热门文章

  1. 广东职称英语计算机考试时间安排,2017年广东省职称计算机考试报名时间
  2. 双色球机选彩票shell脚本
  3. Win系统下打开串口转换USB口的RS232串口,打不开问题
  4. corex9服务器组装攻略,服务器级的X9机箱 只因“发烧”而生_Tt Core X9_机箱电源评测-中关村在线...
  5. 正反转可控的步进电机
  6. 低秩矩阵(Low-Rank)的意义
  7. dell服务器uefi启动不了系统安装系统安装,戴尔做uefi系统-uefi启动进不去系统怎么办呀...
  8. 周日:潭杯山-潭柘寺拉练
  9. 将WORD中的文档编号转换成文字(宏命令法)
  10. 腾讯应用宝整改通知 隐私政策