• java生成pdf


    介绍

    本篇博客主要是为了介绍如何使用:flying-saucer+itext+freemark实现导出复杂点的pdf文件。

    思路

    • 先把pdf的内容以html形式准备好
    • 使用freemarker将html中的动态内容替换掉
    • 使用flying-saucer生成pdf文件

    下载jar包

    <dependency>
        <groupId>org.xhtmlrenderer</groupId>
        <artifactId>flying-saucer-pdf</artifactId>
        <version>9.1.5</version>
    </dependency>
    

    下载中文字体

    搜索:simsun.ttc
    宋体(对应css中的 属性 font-family: SimSun; /宋体/)

    准备好pdf的模板

    把这个模板放到

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html
        PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>准考证</title>
    <style>
    @page {  size: 13.8in 10.4in; }
    </style>
    <!--@page {  size: 13.8in 10.4in; } 这个可以调整pdf页面的大小很好用-->
    </head>
    <body>
    <div style=" 1200px; margin:0 auto; background: #fff; position: relative">
        <img src="/isuyang/images/steam/students.jpg" width="1200px;" alt=""/>
        <span style="color:#333; font-size:12.0pt; font-family: ; position: absolute; top: 63px; left:154px;">${certificateNumber}</span>
        <span style="color:#333; font-size:20.0pt; font-family: SimSun; font-weight: bold; position: absolute; top: 320px; left:236px; 160px; text-align: center">${realName}</span>
        <span style="color:#333; font-size:20.0pt; font-family: SimSun; font-weight: bold; position: absolute; top: 426px; left:236px; 140px; text-align: center">${division}</span>
        <span style="color:#333; font-size:20.0pt; font-family: SimSun; font-weight: bold; position: absolute; top: 426px; left:428px; 140px; text-align: center">${grade}</span>
    
        <span style="color:#333; font-size:20.0pt; font-family: SimSun; font-weight: bold; position: absolute; top: 426px; left:612px; 140px; text-align: center">${prize}</span>
    </div>
    </body>
    </html>
    

    配置Freemaker

    添加引用

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

    在src/main/resource目录下创建ftl.properties文件

    这个文件不一定非得放在这里,只是maven项目约定资源文件的目录是在这。
    ftl的文件内容:

    classic_compatible=true      
    ##如果变量为null,转化为空字符串,比如做比较的时候按照空字符做比较 
    whitespace_stripping=true    
    ##去掉多余的空格,非常有用 
    ##模版更新事件,设置为1秒,正式环境设置为3600秒  
    #template_update_delay=3600 
    template_update_delay=1        
    ##模版更新时间,这里配置是1秒更新一次,正式环境,模版不会改变,可以将这个值设很大,提高效率
    ##locale=zh_CN            
    ##中国 
    default_encoding=utf-8   
    ##编码utf8 
    url_escaping_charset=utf-8  
    ##url编码utf8 
    date_format=yyyy-MM-dd   
    ##显示日期格式 
    time_format=HH:mm:ss       
    ##显示时间格式 
    datetime_format=yyyy-MM-dd HH:mm:ss  
    ##显示日期格式 
    number_format=0.###### 
    ##数字显示格式
    boolean_format=是,否
    ## boolean显示格式
    tag_syntax=auto_detect
    ##设置标签类型 两种:[] 和 <> 。[] 这种标记解析要快些
    

    在ftl.xml文件里配置freemarker.template.Configuration

    记得在spring-context.xml文件里引用这个文件,

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
            http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.1.xsd"
        default-lazy-init="true">
    
        <description>ftl Configuration</description>
    
        <!-- 加载配置属性文件 -->
        <context:property-placeholder ignore-unresolvable="true" location="classpath:config/config.properties" />
        
        <bean id="configuration" class="freemarker.template.Configuration"/>
        
    </beans>
    

    在启动的时候加载配置

    /**
     * 启动
     * <p>
     * 应用的启动入口
     *
     * @author   ZhuangJunxiang(529272571@qq.com)
     * @Date     2017年4月10日
     */
    @Component
    public class Setup implements ServletContextAware {
    
        @Override
        public void setServletContext(final ServletContext context) {
            WebApplicationContext act = ContextLoader.getCurrentWebApplicationContext();
            Configuration ftlConf = (Configuration) act.getBean("configuration");
            FtlUtil.initConfiguration(ftlConf, context, "/", "config/ftl.properties");
        }
    }
    
    

    编写Controller

        /**
         * 下载初赛的pdf证书
         * 
        */
        @Void //这个是自定义注解,可以删除
        @RequestMapping
        @ResponseBody
        public void downloadChuSaiPrizePdf() {
            stemViewService.downloadPdf();
        }
    

    编写steamViewService

       public void downloadPdf() {
            String pdfPath = generatorPdf(getSteamSignup(), "student.ftl");
            boolean exist = FileUtil.isExist(pdfPath);
            if (!exist) {
                throw ExceptionUtil.bEx("PDF不存在");
            }
            try {
                DownloadUtil.download(MvcUtil.getResponse(), pdfPath);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                FileUtil.deleteFile(pdfPath);
            }
        }
       /**
         * 生成pdf
         *
         * @param parameter
         * @return TODO(这里描述每个参数,如果有返回值描述返回值,如果有异常描述异常)
        */
        public String generatorPdf(Map<String, Object> parameter, String ftlPath) {
            //Pdf的存放路径:"G:\pdf\" 这里的路径我是通过配置获取的
            String pdfPath = pdfConfig.getValue("pdfPath") + parameter.get("certificateNumber") + ".pdf";
            //字体的存放路径 这里也是通过配置获取的:可以写:G:\pdf\simsun.ttc
            String font1 = pdfConfig.getValue("fontPath");
    
            OutputStream os = null;
            try {
    
                os = new FileOutputStream(pdfPath);
                ITextRenderer renderer = new ITextRenderer();
                ResourceLoaderUserAgent callback = new ResourceLoaderUserAgent(renderer.getOutputDevice());
    
                renderer.getSharedContext().setUserAgentCallback(callback);
                callback.setSharedContext(renderer.getSharedContext());
                //添加中文字体
                renderer.getFontResolver().addFont(font1, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
                //这里的ftl路径存放在WEB-INF/steam/下
                String repAfterHtml = FtlUtil.build(configuration, "steam/" + ftlPath, parameter);
                renderer.setDocumentFromString(repAfterHtml);
                // 解决图片的相对路径问题,这里也可以写:http://localhost:8080/的形式
                renderer.getSharedContext().setBaseURL("http://static.isuyang.cn/");
                renderer.layout();
                renderer.createPDF(os);
                os.close();
                os = null;
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        // ignore
                    }
                }
            }
            return pdfPath;
        }
        /**
         * 资源加载代理
         *
         */
        private static class ResourceLoaderUserAgent extends ITextUserAgent {
            public ResourceLoaderUserAgent(ITextOutputDevice outputDevice) {
                super(outputDevice);
            }
    
            protected InputStream resolveAndOpenStream(String uri) {
                InputStream is = super.resolveAndOpenStream(uri);
                System.out.println("加载资源文件: " + uri);
                return is;
            }
        }
    

    DownloadUtil.java

    package com.we.core.web.util;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    
    import javax.servlet.http.HttpServletResponse;
    
    import com.we.core.common.util.ExceptionUtil;
    import com.we.core.common.util.FileUtil;
    
    /**
     * 下载方法
     * @author  lq
     * @Date     2014-7-15
     */
    public class DownloadUtil {
    
        public static HttpServletResponse download(final HttpServletResponse response, final String path) throws Exception {
            return download(response, path, null);
        }
    
        public static HttpServletResponse download(final HttpServletResponse response, final String path,
                final String fileName) throws Exception {
            File file = new File(path);
            String fn = fileName;
            if (com.we.core.common.util.Util.isEmpty(fileName)) {
                fn = file.getName();
            } else {
                if (fileName.indexOf(".") == -1) {
                    fn = fileName + "." + FileUtil.getSuffix(file.getName());
                }
            }
            InputStream fis = new BufferedInputStream(new FileInputStream(path));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            response.reset();
            response.addHeader("Content-Disposition", "attachment;filename="
                    + new String(fn.getBytes("gb2312"), "ISO8859-1"));
            response.addHeader("Content-Length", "" + file.length());
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
            return response;
        }
    
        public static HttpServletResponse viewWord(final HttpServletResponse response, final String path) throws Exception {
            try {
                File file = new File(path);
                String filename = file.getName();
                InputStream fis = new BufferedInputStream(new FileInputStream(path));
                byte[] buffer = new byte[fis.available()];
                fis.read(buffer);
                fis.close();
                response.reset();
                response.addHeader("Content-Disposition", "inline;filename="
                        + new String(filename.getBytes("gb2312"), "ISO8859-1"));
                OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
                response.setContentType("application/pdf");
                toClient.write(buffer);
                toClient.flush();
                toClient.close();
            } catch (Exception e) {
                throw ExceptionUtil.bEx("文件损坏,预览失败");
            }
            return response;
        }
    
        public HttpServletResponse viewTxt(final HttpServletResponse response, final String path) throws Exception {
            try {
                BufferedReader bis = null;
                File file = new File(path);
                InputStream in = new FileInputStream(file);
                bis = new BufferedReader(new InputStreamReader(in));
                StringBuffer buf = new StringBuffer();
                String temp;
                while ((temp = bis.readLine()) != null) {
                    buf.append(temp);
                    response.getWriter().write(temp);
                    if (buf.length() >= 1000) {
                        break;
                    }
                }
                bis.close();
            } catch (Exception e) {
                throw ExceptionUtil.bEx("文件损坏,预览失败");
            }
            return response;
        }
    }
    
    

    效果

    建议

    最好参考官方文档,因为好多写的都是不全,还有就是在搜索百度的时候一定要搜索博客靠前的文章,可以使用百度的搜索工具过滤一下。
    https://developers.itextpdf.com/examples/xml-worker-itext5/html-images

  • 相关阅读:
    Microsoft office 2013安装图解
    6.2单一继承
    #include <QLabel>
    #include <QDebug>
    9.1运算符重载
    简单QT界面信号图形化输入输出
    类指针引用
    NULL和nullptr的区别
    网易云课堂_C语言程序设计进阶_第8周:图形交互程序
    5.3友元函数
  • 原文地址:https://www.cnblogs.com/wangsen/p/9329687.html
Copyright © 2020-2023  润新知