Java PDF生成方案之iText

 

我是不会告诉你,关注公众号《andyqian》,回复pdf,会给你整个工程代码的!

前言

  这是一篇以前的文章,最近做了优化处理,决定分享在这里,没有时间阅读全文的童鞋,可直接拖到最后一章节。进入主题,今天介绍的是电子凭证(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平台下还是有些问题的,字体路径会加载不到,处理方案,请看下一章节。

福利时间 | 现成代码

我是不会告诉你,关注公众号《andyqian》,回复pdf,会给你整个工程代码的!

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

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,希望能够帮助到你。

 

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

 

092341_fEn4_1462914.gif

扫码关注,一起进步

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

转载于:https://my.oschina.net/u/1462914/blog/1584269

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值