1. 程式人生 > >使用freemarker+itextpdf通過HTML模版匯出PDF

使用freemarker+itextpdf通過HTML模版匯出PDF

一 簡介

     因公司業務需求需要做一個通過模版匯出PDF的功能,模版是word文件,模版中包含圖片,文字,水印,分頁。遇到這種沒做過的功能,沒什麼可說的,直接問度娘。結果度娘給不了我想要的,只好去github上下了一些相關的專案,通過篩選和實驗終於找到了不錯的程式碼,但是在使用過程中也是踩了無數坑,隨記錄下來。

二 思路

   通過模版匯出PDF的方法有很多,但是思路都大致相同,總結起來就是 渲染模版 2 匯出模版。以為之前使用過freemarker,所以我這裡渲染模版的技術用的是freemarker,然後在使用itextpdf將渲染好的模版匯出。

三 踩過的坑

1 Win下中文不顯示 2 圖片不顯示 3 Linux下中文不顯示 4 圖片樣式跑偏 5 分頁加水印

四 上程式碼

4.1 準備工作

4.11首先準備好一個word模版,如下圖所示


4.1.2 將word模版通過wps或其他工具另存為  轉為HTML模版.

轉為html後 ${}會被 分開,通過線上格式化工具排版HTML,將${}之間多餘的程式碼刪掉,重新恢復到${},批量操作即可.

4.1.3 新建一個ftl檔案,將HTML程式碼拷貝進去 如下圖所示

4.1.4 maven座標

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.23</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.0.3</version>
        </dependency>

4.2 寫程式碼 新建一個PDF工具類

4.2.1 第一步 渲染模版 程式碼如下

      //獲取模板並填充資料
      public static String getContent(String fileName,Object data) throws Exception{
           // 建立一個Configuration物件
            Configuration configuration = new Configuration(Configuration.getVersion());
            Configuration config = new Configuration(Configuration.getVersion());//FreeMarker配置
           // 告訴config物件模板檔案存放的路徑。
           configuration.setDirectoryForTemplateLoading(new File(PdfUtil.class.getClassLoader().getResource("templates/").getPath()));
          // 設定config的預設字符集。一般是utf-8
          configuration.setDefaultEncoding("utf-8");
          //從config物件中獲得模板物件。需要制定一個模板檔案的名字。
          Template template = configuration.getTemplate(fileName+".ftl");
          StringWriter writer = new StringWriter();
          //模版和資料匹配
          template.process(data, writer);
          writer.flush();
          String html = writer.toString();
          return getImgs(html);
      }

4.2.2 第二步 替換模版中的圖片路徑 程式碼如下

    //替換html中的圖片路徑
    private static String getImgs(String content) {
        String img = "";
        Pattern p_image;
        Matcher m_image;
        String str = "";
        String[] images = null;
        String regEx_img = "(<img.*src\\s*=\\s*(.*?)[^>]*?>)";
        p_image = Pattern.compile(regEx_img, Pattern.CASE_INSENSITIVE);
        m_image = p_image.matcher(content);
        if(m_image!=null){
            while (m_image.find()) {
                img = m_image.group();
                Matcher m = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)")
                        .matcher(img);
                if(m!=null){
                    while (m.find()) {
                        String tempSelected = m.group(1);
                        str = tempSelected;
                        String classpath= PathUtil.getRootPath();
                        String ulr=classpath.substring(5,classpath.length());
                        content=content.replace(str,ulr+"templates/"+str);
                    }
                }
            }
        }
       return content;
    }

工具類 PathUtil

/**
 * @author:change
 * @description:獲取絕對路徑
 * @date:2018/6/28 0028
 */
public class PathUtil {
   static String path1;
    static String download;

    public static String getRootPath() {
        String line = File.separator;
        String path = Thread.currentThread().getContextClassLoader().getResource("").toString();
        //windows下
        if ("\\".equals(line)) {
/*            path = path.replace("/", "\\");  // 將/換成\\*/
            path1 = path;
        }
        //linux下
        if ("/".equals(line)) {
            path = path.replace("\\", "/");
            path1 = path;
        }
        return path1;
    }

    public static void main(String[] args) {
        System.out.println(getRootPath());
        System.out.println(PdfUtil.class.getClassLoader().getResource("").getPath());
    }
}

4.2.3 設定pdf字符集 程式碼如下

 /**
     * 設定字符集
     */
    public static class MyFontsProvider extends XMLWorkerFontProvider {


        public MyFontsProvider(){
            super(null, null);
        }

        @Override
        public Font getFont(final String fontname, String encoding, float size, final int style) {
            String fntnames = fontname;
            Font FontChinese = null;
            if (fntnames == null) {
                fntnames = "宋體";
            }
            if (size == 0) {
                size = 4;
            }
            try{
                BaseFont bfChinese = BaseFont.createFont("STSong-Light",
                        "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                FontChinese = new Font(bfChinese, 12, Font.NORMAL);
            }catch (Exception e){
                e.printStackTrace();
            }
            if(FontChinese==null){
                FontChinese = super.getFont(fntnames, encoding, size, style);
            }
            return FontChinese;
        }
    }

4.2.4 生產PDF並下載 程式碼如下

    /**
     * 生成PDF到輸出流中(ServletOutputStream用於下載PDF)
     * @param templateName ftl模板名稱
     * @param data 輸入到FTL中的資料
     * @param response HttpServletResponse
     * @return
     */
    public static OutputStream exportToResponse(String templateName, Object data,
                                         HttpServletResponse response)throws Exception{
        TEMPLATENAMES=templateName;
        String html= getContent(templateName,data);
        response.reset();
        response.setContentType("application/pdf;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename="+ new String((templateName + ".pdf").getBytes(), "iso-8859-1"));
        try{
            OutputStream out = null;
            ITextRenderer render = null;
            out = response.getOutputStream();
            //設定文件大小
            Document document = new Document(PageSize.A4);
            PdfWriter writer = PdfWriter.getInstance(document, out);
            writer.setStrictImageSequence(true);
            //輸出為PDF檔案
            convertToPDF(writer,document,html);
            return out;
        }catch (Exception ex){
            System.out.println(ex);
            throw  new SimpleException("PDF export to response fail");
        }

    }

    /**
     * @description PDF檔案生成
     */
    private  static void convertToPDF(PdfWriter writer,Document document,String htmlString)throws Exception{
        document.open();
        MyFontsProvider fontProvider = new MyFontsProvider();
        fontProvider.addFontSubstitute("lowagie", "garamond");
        fontProvider.setUseUnicode(true);
        CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
        HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
        htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
        XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
         if(TEMPLATENAMES.equals("合同")||TEMPLATENAMES.equals("合同模版"))
         writer.setPageEvent(new BackGroundImage());
         if(TEMPLATENAMES.equals("設計合同"))
         writer.setPageEvent(new SheJiGroundImage()); //這裡初始化分頁監聽類
        try {
            XMLWorkerHelper.getInstance().parseXHtml(writer,document,
                    new ByteArrayInputStream(htmlString.getBytes("UTF-8")),
                    XMLWorkerHelper.class.getResourceAsStream("/default.css"),
                    Charset.forName("UTF-8"),fontProvider);
        } catch (IOException e) {
            e.printStackTrace();
            throw new SimpleException("PDF檔案生成異常");
        }finally {
            document.close();
        }

    }

4.2.5 設定水印和分業  新建一個類繼承pdfPageEventHelper ,該類用來監聽pdf分頁 程式碼如下

package com.rxjy.commons.pdf;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfWriter;
import com.rxjy.constructionContract.myutils.PathUtil;

import java.io.IOException;

/**
 * @author:change
 * @description:監聽分頁
 * @date:2018/7/2 0002
 */
public class BackGroundImage extends PdfPageEventHelper {

    String classpath= PathUtil.getRootPath();
    String ulr=classpath.substring(5,classpath.length());

    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        try {
            if(document.getPageNumber()==1){ //第一頁
                Image image = Image.getInstance(ulr+"templates/合同.files/合同39.png"); //甲方
                Image image1 = Image.getInstance(ulr+"templates/合同.files/合同242.png"); //乙方
                /* 設定圖片的大小 */
                image.scaleAbsolute(128, 128);
                image1.scaleAbsolute(128, 128);
                /* 設定圖片的位置 */
                image.setAbsolutePosition(70,600);
                image1.setAbsolutePosition(300,600);
                document.add(image);
                document.add(image1);
                //二維碼
                Image code = Image.getInstance(ulr+"templates/合同.files/合同二維碼.png");
                code.scaleAbsolute(50,50);
                code.setAbsolutePosition(500,750);
                document.add(code);
            }
            if(document.getPageNumber()==4){ //第四頁
                Image image = Image.getInstance(ulr+"templates/合同.files/合同39.png"); //甲方
                Image image1 = Image.getInstance(ulr+"templates/合同.files/合同242.png"); //乙方
                /* 設定圖片的大小 */
                image.scaleAbsolute(128, 128);
                image1.scaleAbsolute(128, 128);
                 /* 設定圖片的位置 */
                image.setAbsolutePosition(70,350);
                image1.setAbsolutePosition(300,350);
                document.add(image);
                document.add(image1);
            }
            //分頁水印
            Image yejiao = Image.getInstance(ulr+"templates/合同.files/合同"+document.getPageNumber()+".png");
            yejiao.scaleAbsolute(144,44);
            yejiao.setAbsolutePosition(450,30);
            document.add(yejiao);
        } catch (BadElementException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        }

    }
}

4.2.6 呼叫PDF工具類 程式碼如下

@ApiOperation("匯出合同")
    @GetMapping("/importPdfByTemplates")
    void importPdfByTemplates(HttpServletResponse response,String rwdid,String templateName)throws Exception{
        Map<String,Object> map=heTongService.htInfoMap(rwdid); //該資料的key對應模版中的${}中的欄位
  
        PdfUtil.exportToResponse(templateName,map,response);
    } 

五 測試

匯出的PDF若遇到樣式上的細微問題。可以在ftl中使用html程式碼調整  諮詢相關問題請加群.

效果圖

相關推薦

使用freemarker+itextpdf通過HTML模版匯出PDF

一 簡介     因公司業務需求需要做一個通過模版匯出PDF的功能,模版是word文件,模版中包含圖片,文字,水印,分頁。遇到這種沒做過的功能,沒什麼可說的,直接問度娘。結果度娘給不了我想要的,只好去github上下了一些相關的專案,通過篩選和實驗終於找到了不錯的程式碼,但是

關於通過iText通過HTML轉成PDF匯出的操作遇到一些問題的記錄

最近做專案,有一個pdf匯出的操作,是通過html轉成pdf做的匯出,遇到的一些問題分享出來,希望大家以後做匯出pdf的時候注意: 第一:html匯出為pdf是通過XMLWorkerHelper.getInstance().parseXHtml(pdfwriter, doc

java 實現html模板匯出pdf的方式

最近在工作中遇到了一個很囧的事情。要把HTML頁面轉換成PDF或者tiff圖片等其他形式,目前tiff還是一頭霧水,如果各位大師有真的可行的想法(不要是別人那邊抄的,百度最近搜尋的質量嚴重的打擊了我對國貨的信心。)希望能夠告訴我,先謝了。 言歸正傳。所以,我就做了把H

JAVA按模版匯出PDF檔案,含條碼,二維碼,表格

示例模版: 示例匯出: 核心程式碼: package com.yonyou.dms.framework.service.pdf; import java.io.ByteArrayOutputStream; import java.io.File; import ja

iOS通過html模版實現富文字編輯

 在iOS開發中,常常會遇到一些富文字編輯,如新聞,公告等,NSMutableAttributedString又有一定的侷限性,所以我想到用html 模版去載入富文字頁面,根據所需要的格式,去構建相應的html介面。一個簡單的html模版如下: <!DOCTYP

用js 將當前html頁面匯出pdf

引入的js <script src="./js/libs/jquery-2.0.2.js"></script> <script src="./js/exportpdf/jspdf.debug.js"></script>

ASP.NET C#根據HTML頁面匯出PDF

在啟明星採購系統裡,新增了匯出PDF功能。整個功能使用了第三方軟體 wkhtmltopdf(下載) 官網 https://wkhtmltopdf.org/ 提供有更多版本下載 他可以把HTML頁面轉換為PDF,該軟體簡直是incredible-不可思議了,功能太強大了。

html模板匯出pdf檔案

程式碼如下: import java.awt.Insets; import java.io.ByteArrayOutputStream; import java.io.StringReader; import org.apache.commons.logging.Log

itext應用HTML模版生成PDF並加水印,處理了中文問題

剛用itext實現了一個生成PDF加水印 其中遇到的問題是它對中文支援不好,專門寫了對中文的處理 先看效果圖: maven包 <dependency> <groupId>

使用itextpdfhtml 轉成 pdf遇到的坑

 這幾天磨磨唧唧在整理html轉pdf這一個功能,還好領導不急。讓我慢慢整。流程基本已明確了,我們這邊從協同那邊同步資料,然後銷售在後臺生成連結發給客戶,然後客戶在H5(jSignature)好籤名上傳將簽名儲存成png檔案,再將png檔案壓到pdf的指定位置上。   

通過html文件生成PDF文件

window log get name time pub open vat folder /// <summary>/// 獲取html內容,轉成PDF(註冊)/// </summary>public void DownloadPDFByHTML(s

html匯出pdf的四種方式

將html頁面匯出為pdf檔案並列印,可以直接在windows下使用Ctrl + P,蘋果下⌘ + P。 如果需要用程式碼實現,可以考慮jsPDF、iText、wkhtmltopdf等方式。 以下是三種方式程式碼對比: 方式 優點 缺點 分頁 圖片 表

html匯出pdf

<!-- html轉PDF --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>kernel</artifactId>

使用iText 將html頁面轉PDF檔案(itext+freemarker

1.匯入jar包(使用maven管理) <!--itext start--> <dependency> <groupId>com.lowagie&l

HTML TABLE 細邊框樣式 用HTML作為模板,JAVA匯出PDF相容table樣式

    在平時用css寫html table細邊框樣式時候,有很多種寫法,但是發現用JAVA匯出PDF,用HTML作為模板的時候,在轉換時出現樣式不相容問題,經過測試,以下樣式可以完美相容。     現整理如下: <style> table {

Itext 匯出PDF(中文解決,HTMLPDF

iText是著名的開放原始碼的站點sourceforge一個專案,是用於生成PDF文件的一個java類庫。通過iText不僅可以生成PDF或rtf的文件,而且可以將XML、Html檔案轉化為PDF檔案。 iText的安裝非常方便,下載iText.jar檔案後,只需要在系統的

Java HTML匯出PDF (一)

1、IText實現html2pdf,速度快,糾錯能力差,支援中文(要求HTML使用unicode編碼),但中支援一種中文字型,開源。 2、Flying Sauser實現html2pdf,糾錯能力差,支援多種中文字型(部分樣式不能識別),開源。 3、PD4ML

通過潤乾API實現raq後臺匯出pdf

一、問題描述 客戶希望在JSP展現raq檔案的同時後臺將該raq匯出為pdf,儲存在相關路徑下。 二、解決思路 通過潤乾API實現該功能。 三、實現步驟 <%@pagecontentType="text/html;charset=gb2312"%>

java通過htmlpdf

HTML轉PDF工具(wkhtmltopdf)介紹,支援widows和linux wkhtmltopdf下載地址:連結:http://pan.baidu.com/s/1jIkk9Wa 密碼:ljn6 cmd用法: java用法: package

freemarker+ITextRenderer 生成htmlpdf

網上已經有比較多的例子 寫這個 但是很多都是簡單的 demo,而且有很多隱藏的問題 或者是零散的 對某些問題的解決方案 本人再次寫一個完整的demo  無bug 可用 我是在spring mvc中應用的  Java程式碼   String basePath = req