java生成pdf

介紹

本篇博客主要是爲了介紹如何使用:flying-saucer+itext+freemark實現導出複雜點的pdf文件。css

思路

  • 先把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; /宋體/)html

準備好pdf的模板

把這個模板放到
java

<?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="width: 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;width: 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;width: 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;width: 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;width: 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的文件內容:web

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文件裏引用這個文件,
spring

<?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.javaapi

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-imagesapp

相關文章
相關標籤/搜索