Java PDF生成方案之iText


声明:本文转载自https://my.oschina.net/u/1462914/blog/1584269,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

Java PDF生成方案之iText

本文首发于个人微信公众号《andyqian》,期待你的关注!

前言

  这是一篇以前的文章,最近做了优化处理,决定分享在这里,没有时间阅读全文的童鞋,可直接拖到最后一章节。进入主题,今天介绍的是电子凭证(pdf)生成的解决方案,会从几个常用的工具来介绍,也会对比一下几者之间的性能。

iText是什么?

在官网中 http://itextpdf.com/描述:

iText, the world's preferred PDF library,iText is a software developer toolkit that allows users to integrate PDF functionalities within their applications, processes or products

iText,是世界上首选的PDF库,iText是一个软件开发人员工具包,允许用户将PDF功能集成到其他应用程序,流程或者产品中。 其特点有:

  1. 支持表格
  2. 图片,
  3. 定制字体
  4. 支持合并pdf 等。

准备工作

在使用iTex时,我们需要添加Maven依赖,如下:

<dependency>       <groupId>com.itextpdf</groupId>       <artifactId>itextpdf</artifactId>       <version>5.5.11</version>     </dependency>

入门实例

代码:

/**      * 生成pdf文件      */     @Test     public void testCreatePdf(){         try{         // 1. new Document         Document document = new Document();         PdfWriter.getInstance(document, new FileOutputStream(DEST));         // 2. 打开document         document.open();         // 3. 添加内容         document.add(new Paragraph("hello world!"));         // 4. 关闭 (如果未关闭则会生成无效的pdf文件)         document.close();         }catch(DocumentException ex){             ex.printStackTrace();         }catch (FileNotFoundException ex){             ex.printStackTrace();         }     }

效果:
helloWorld

iText字体

iText内置支持多种字体,我们可以通过FontFactory类找到iText的内置字体:

Courier; Courier-Bold; Courier-Oblique; Courier-BoldOblique; Helvetica; Helvetica-Bold; Helvetica-Oblique; Helvetica-BoldOblique; Symbol; Times; Times-Roman; Times-Bold; Times-Italic; Times-BoldItalic; ZapfDingbats;

同样,iText也允许自定义字体,itext默认字体不支持中文,这时,我们就可以通过自定义字体来解决这个问题,代码如下所示:

@Test     public void testChineseFontPdf(){         try {             //1. new document             Document document = new Document();             PdfWriter.getInstance(document, new FileOutputStream("/tmp/pdf/2017/1.pdf"));             //2. open document             document.open();             BaseFont bf = BaseFont.createFont(path()+"fonts/SIMKAI.TTF", BaseFont.IDENTITY_H,BaseFont.EMBEDDED);             //3. 注册字体             Font font = new Font(bf,30);             //3. 添加段落,并设置字体             document.add(new Paragraph("hello world(中文,)",font));             //4. close document             document.close();         }catch(FileNotFoundException ex){             ex.printStackTrace();         }catch(DocumentException ex){             ex.printStackTrace();         }catch(IOException ex){             ex.printStackTrace();         }     }       /**      * 获取资源的路径      * @return      */     private String path(){         String path = this.getClass().getResource("/").getPath();         return path;     }

效果如下: 中文

表格

通常我们会在pdf文件中生成表格,来展示数据,在iText中也是非常方便的,代码如下:

/**      * 生成表格      */     @Test     public void testTablePdf(){         try {             //1.new document             Document document = new Document();             PdfWriter.getInstance(document,new FileOutputStream("/tmp/pdf/2017/1.pdf"));             //2 open document             document.open();             //3.添加pdf tables 3表示列数,             PdfPTable pdfPTable = new PdfPTable(3);             // cell表示单元格,(12表示12个单元格,3列,12个单元格就形成来一个4行3列的表格)             for (int i = 0; i < 12; i++) {                 pdfPTable.addCell("cell" + i);             }             document.add(pdfPTable);             //4. 关闭document             document.close();         }catch(DocumentException ex){             ex.printStackTrace();         }catch(FileNotFoundException ex){             ex.printStackTrace();         }     }

生成效果如下所示:
表格

图片

代码:

/**      * 生成image      */     @Test     public void testImagePdf(){         try {             //1.new document             Document document = new Document();             PdfWriter.getInstance(document,new FileOutputStream("/tmp/pdf/2017/1.pdf"));             //2 open document             document.open();             document.add(new Paragraph("Hello world!"));             //3.添加image             Image image = Image.getInstance(path()+"/images/timg.jpg");             image.scaleAbsolute(PageSize.A4.rotate());             document.add(image);             //4. 关闭document             document.close();         }catch(DocumentException ex){             ex.printStackTrace();         }catch(FileNotFoundException ex){             ex.printStackTrace();         }catch (IOException ex){             ex.printStackTrace();         }     }

效果:
表格

html转换pdf

我们在实际项目中,需要将html格式的文档转换为pdf工具,在iText中,默认是不直接支持html格式文档的,我们可以借助com.itextpdf.tool来生成 首先添加maven

<dependency>       <groupId>com.itextpdf.tool</groupId>       <artifactId>xmlworker</artifactId>       <version>5.5.11</version>     </dependency>

代码如下所示:

/**  * author: andy  * date: 17-5-30  * blog: www.andyqian.com  * version: 0.0.1  * description: 生成html格式內容的工具類  */ public class CreateHtmlPdfTest {      /**      * html内容路径      */     private static final String HTML_PATH= "/html/helloworld.html";     private static final String FONT_PATH="/fonts/SIMKAI.TTF";      /**      * 生成pdf格式的內容      */     @Test     public void testHtml(){         try {             //1. new document             Document document = new Document();             PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("/tmp/pdf/2017/1.pdf"));             //2.open document             document.open();             //3. 设置字体             XMLWorkerFontProvider xmlWorkerFontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);             xmlWorkerFontProvider.register(getContextPath()+FONT_PATH);             //4. 文件             FileInputStream fileInputStream = new FileInputStream(getContextPath()+HTML_PATH);             XMLWorkerHelper.getInstance().parseXHtml(writer, document,fileInputStream, Charset.forName("UTF-8"),xmlWorkerFontProvider);             //3. close document             document.close();         }catch(Exception ex){             ex.printStackTrace();         }     }      /**      * 获取上下文路径      * @return      */     private String getContextPath(){         return this.getClass().getResource("/").getPath();     } }

html代码内容:

<!DOCTYPE html> <html lang="en"> <head>     <meta charset="UTF-8"/>     <title>标题</title> </head> <style>     *{         font-family: KaiTi_GB2312;     } </style> <body>     hello world! XMLWorkerHelper [这是带有中文的html格式内容] </body> </html>

代码结构为:
项目结构效果如下所示:
带中文的html

7.iText+Freemarker

首先添加Freemarker Maven依赖如下所示:

<dependency>       <groupId>org.freemarker</groupId>       <artifactId>freemarker</artifactId>       <version>2.3.23</version>     </dependency>

代码如下所示:

/**  * author: andy  * date: 17-5-30  * blog: www.andyqian.com  * version: 0.0.1  * description: 通过feemarker工具类生成pdf  */ public class CreateFeemarkerPdfTest {      private static final String FONT_PATH="/fonts/SIMKAI.TTF";     private static final String HTML_PATH="/html/feemarker.html";      @Test     public void testCreatePdf(){             try {                 //1. new document                 Document document = new Document();                 PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("/tmp/pdf/2017/1.pdf"));                 //2.open document                 document.open();                 //3. 设置字体                 XMLWorkerFontProvider xmlWorkerFontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);                 xmlWorkerFontProvider.register(getContextPath()+FONT_PATH);                  //4. 设置模板内容                 Map<String,Object> params = new HashMap<String,Object>();                 params.put("name","鞠骞");                 params.put("career","软件开发");                 params.put("blog","http://www.andyqian.com");                 String content = getFreeMarkerText(htmlContent(),params);                 //4. 文件                 InputStream inputStream = new ByteArrayInputStream(content.getBytes("utf-8"));                 XMLWorkerHelper.getInstance().parseXHtml(writer, document,inputStream, Charset.forName("UTF-8"),xmlWorkerFontProvider);                 //3. close document                 document.close();             }catch(Exception ex){                 ex.printStackTrace();             }         }      /**      * 获取上下文路径      * @return      */     private String getContextPath(){         return this.getClass().getResource("/").getPath();     }      /**      * freemarker模板方法      * @param templateTxt 模板文本      * @param map  模板参数      * @return      * @throws Exception      */     public static String getFreeMarkerText(String templateTxt, Map<String, Object> map) throws Exception {         String result = null;         Configuration config = new Configuration(Configuration.VERSION_2_3_23);         try {             StringTemplateLoader e = new StringTemplateLoader();             e.putTemplate("t", templateTxt);             config.setTemplateLoader(e);             config.setDefaultEncoding("UTF-8");             Template template = config.getTemplate("t", "UTF-8");             StringWriter out = new StringWriter();             template.process(map, out);             result = out.toString();             return result;         } catch (IOException iex) {             throw new Exception("获取freemark模版出错", iex);         } catch (TemplateException ex) {             throw new Exception("freemark模版处理异常", ex);         }     }      /**      * 获取html内容      * @return      */     private String htmlContent(){         String result = "";         try {             FileInputStream fileInputStream = new FileInputStream(getContextPath() + HTML_PATH);             int len=0;             byte[] array = new byte[1024];             StringBuffer stringBuffer = new StringBuffer();             while((len=fileInputStream.read(array))!=-1){                 stringBuffer.append(new String(array,0,len));             }             result = stringBuffer.toString();         }catch(Exception ex){             ex.printStackTrace();         }         return result;     } }

效果如下:
freemarker

其实上面,在windows平台下还是有些问题的,字体路径会加载不到,处理方案,请看下一章节。

福利时间 | 现成代码

如果想拷贝代码直接使用,也可以使用下面代码

public class PdfUtils {          private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);          /**          * 通过html生成文件          * @param htmlContent  html格式内容          * @param file  输出文件file          */         public static void createdPdfByItextHtml(String htmlContent,File file){             InputStream inputStream = null;             FileOutputStream outputStream = null;             PdfWriter writer = null;             try {                 // 1. 获取生成pdf的html内容                 inputStream= new ByteArrayInputStream(htmlContent.getBytes("utf-8"));                 outputStream = new FileOutputStream(file);                 Document document = new Document();                 writer = PdfWriter.getInstance(document, outputStream);                 document.open();                 // 2. 添加字体                 XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);                 fontImp.register(getFontPath());                 // 3. 设置编码                 XMLWorkerHelper.getInstance().parseXHtml(writer, document, inputStream, Charset.forName("UTF-8"),fontImp);                 // 4. 关闭,(不关闭则会生成无效pdf)                 document.close();             } catch (Exception ex) {                 ex.printStackTrace();             }finally {                 try {                     if(writer!=null){                         writer.close();                     }                     if (outputStream != null) {                         outputStream.close();                     }                     if (inputStream != null) {                         inputStream.close();                     }                 }catch(IOException ex){                     ex.printStackTrace();                 }             }         }      /**      * 应用场景:      * 1.在windows下,使用Thread.currentThread()获取路径时,出现空对象,导致不能使用      * 2.在linux下,使用PdfUtils.class获取路径为null,      * 获取字体路径      * @return      */     private static String getFontPath(){         String path="";         // 1.          ClassLoader classLoader= Thread.currentThread().getContextClassLoader();         URL url = (classLoader==null)?null:classLoader.getResource("/");         String threadCurrentPath = (url==null)?"":url.getPath();         // 2. 如果线程获取为null,则使用当前PdfUtils.class加载路径         if(StringUtil.isBlank(threadCurrentPath)){              path = PdfUtils.class.getClass().getResource("/").getPath();         }         // 3.拼接字体路径         StringBuffer stringBuffer = new StringBuffer(path);         stringBuffer.append("/fonts/SIMKAI.TTF");         path = stringBuffer.toString();         logger.info("getFontPath threadCurrentPath: {}  path: {}",threadCurrentPath,path);         return path;     }

上面getFontPath()方法中,对linux以及windows平台做了字体加载路径做了兼容处理。

参考资料

  1. http://developers.itextpdf.com/developers-home
  2. http://itextpdf.com/

小结

本文从iText最基本的用法,分别介绍从表格,图片,HTML,Feemarker来介绍iText,希望能够帮助到你。

 

有任何问题,都可以在公众号下留言哦,在线提供帮助!

 

扫码关注,一起进步

个人博客: http://www.andyqian.com

本文发表于2017年12月04日 10:38
(c)注:本文转载自https://my.oschina.net/u/1462914/blog/1584269,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2064 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1