使用IText5+Freemarker生成PDF(模板可以使用CCS3分頁效果)

iText介紹

  iText是著名的開放源碼的站點sourceforge一個項目,是用於生成PDF文檔的一個java類庫。通過iText不僅可以生成PDF或rtf的文檔,而且可以將XML、Html文件轉化爲PDF文件。iText5是目前比較主流使用的因爲免費,iText7是更好但收費的,所以這裏我們還是乖乖使用5吧!!

項目要使用iText,必須引入jar包。才能使用,maven依賴如下:

<!-- itextpdf,導出pdf核心架包 -->
		<dependency>
		  <groupId>com.itextpdf</groupId>
		  <artifactId>itextpdf</artifactId>
		  <version>5.5.11</version>
		</dependency>
		<!-- itextpdf工具包,用來解析html生成pdf -->
		<dependency>
		  <groupId>com.itextpdf.tool</groupId>
		  <artifactId>xmlworker</artifactId>
		  <version>5.5.11</version>
		</dependency>
<!-- flying saucer,支持對CSS高級特性的解析 -->
		 <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>flying-saucer-pdf</artifactId>
            <version>9.1.6</version>
        </dependency>

其中

(1)com.itextpdf是必須的。

(2)com.itextpdf.tool是爲了Freemarker的模板。

(3)org.xhtmlrenderer是爲模板可以使用css3。

IText如果使用的字體是需要我們配置的,這個方式很好,我們可以引用主流或者自己喜歡的字體

網上都可以下載找到的,如果懶可以去這裏下載【字體】

然後我們先來熱熱身

建立一個簡單的pdf

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
 
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;

public class JavaToPdfHtml {


    private static final String DEST = "D:/pdf/template.pdf";//輸出地址
    private static final String HTML = "D:/pdf/template.html";
    private static final String FONT = "D:/pdf/simhei.ttf";
  
  
    public static void main(String[] args) throws IOException, DocumentException {
        // step 1
        Document document = new Document();
        // step 2
        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(DEST));
        // step 3
        document.open();
        // step 4
        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
        fontImp.register(FONT);
        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
                new FileInputStream(HTML), null, Charset.forName("UTF-8"), fontImp);
        // step 5
        document.close();
    }
    
   
}

template.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<style>
body {
	font-family: SimHei;
}

.red {
	color: red;
}
</style>
</head>
<body>

	<div class="red">hello world!</div>
	<div class="red">你好,祖克</div>
</body>
</html>

效果:

 

好,然後我們再來加上Freemarker

package com.jy.pdf;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;

import freemarker.template.Configuration;
import freemarker.template.Template;
  
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

public class JavaToPdfHtmlFreeMarker {
	
	  	private static final String DEST = "D:/pdf/templateF.pdf";
	  	
	    private static final String FTL = "D:/pdf/";
	  	
	  
	    private static final String HTML = "templateF.html";
	    
	    private static final String FONT = "D:/pdf/simhei.ttf";
	  
	    private static Configuration freemarkerCfg = null;
	  
	    static {
	        freemarkerCfg =new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
	        //freemarker的模板目錄
	        try {
	        	//freemarkerCfg.
	           freemarkerCfg.setDirectoryForTemplateLoading(new File(FTL));
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	  
	  

	  
	  
	    public static void createPdf(String content,String dest) throws IOException, DocumentException {
	        // step 1
	        Document document = new Document();
	        // step 2
	        PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
	        // step 3
	        document.open();
	        // step 4
	        XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
	        fontImp.register(FONT);
	        XMLWorkerHelper.getInstance().parseXHtml(writer, document,
	                new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), fontImp);
	        // step 5
	        document.close();
	  
	    }
	  
	    /**
	     * freemarker渲染html
	     */
	    public static String freeMarkerRender(Map<String, Object> data, String htmlTmp) {
	        Writer out = new StringWriter();
	        try {
	            // 獲取模板,並設置編碼方式
	            Template template = freemarkerCfg.getTemplate(htmlTmp);
	            template.setEncoding("UTF-8");
	            // 合併數據模型與模板
	            template.process(data, out); //將合併後的數據和模板寫入到流中,這裏使用的字符流
	            out.flush();
	            return out.toString();
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally {
	            try {
	                out.close();
	            } catch (IOException ex) {
	                ex.printStackTrace();
	            }
	        }
	        return null;
	    }
	    
	    public static void main(String[] args) throws IOException, DocumentException {
	        Map<String,Object> data = new HashMap();
	        data.put("name","路飛.祖克");
	        String content = JavaToPdfHtmlFreeMarker.freeMarkerRender(data,HTML);
	        JavaToPdfHtmlFreeMarker.createPdf(content,DEST);
	    }
}

 

templateF.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
<style>
body {
	font-family: SimHei;
}

.red {
	color: red;
}
</style>
</head>
<body>

	<div class="red">hello world!</div>
	<div class="red">你好,${name}</div>
</body>
</html>

 

效果

 

加入ccs3,圖片使用64位即可

package com.jy.pdf;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.BaseFont;

import freemarker.template.Configuration;
import freemarker.template.Template;
public class JavaToPdfHtmlFreeMarkerCss {


	
  	private static final String DEST = "D:/pdf/templateFCss.pdf";	
    private static final String FTL = "D:/pdf/";	
    private static final String HTML = "templateFCss.html";
    private static final String FONT = "D:/pdf//simhei.ttf";
    private static final String FONT_C = "D:/pdf//calibri.ttf";
    private static final String FONT_S = "D:/pdf//simsun.ttc";
    
    private static final String LOGO_PATH = "D:/pdf/logo.jpg";
    
    private static Configuration freemarkerCfg = null;
  
    static {
    	 freemarkerCfg =new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        //freemarker的模板目錄
        try {
            freemarkerCfg.setDirectoryForTemplateLoading(new File(FTL));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  
    public static void main(String[] args) throws IOException, DocumentException, com.lowagie.text.DocumentException {
        Map<String,Object> data = new HashMap<String,Object>();
        data.put("name","路奇.D.艾尼路 儸傑");
        File file=new File(LOGO_PATH);
        data.put("fileType","image/jpeg");
        data.put("file64Str",fileToBase64Str(file));
        String content =freeMarkerRender(data,HTML);
        //System.out.println(content);
        createPdf(content,DEST);

    }
  
    /**
     * freemarker渲染html
     */
    public static String freeMarkerRender(Map<String, Object> data, String htmlTmp) {
        Writer out = new StringWriter();
        try {
            // 獲取模板,並設置編碼方式
            Template template = freemarkerCfg.getTemplate(htmlTmp);
            template.setEncoding("UTF-8");
            // 合併數據模型與模板
            template.process(data, out); //將合併後的數據和模板寫入到流中,這裏使用的字符流
            out.flush();
            return out.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }
  
    public static void createPdf(String content,String dest) throws IOException, DocumentException, com.lowagie.text.DocumentException {
        ITextRenderer render = new ITextRenderer();
        
        //設置字體
        ITextFontResolver fontResolver = render.getFontResolver();
        fontResolver.addFont(FONT_S, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        fontResolver.addFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        fontResolver.addFont(FONT_C, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        // 解析html生成pdf
        render.setDocumentFromString(content);
        render.layout();
        render.createPDF(new FileOutputStream(dest));
        render.finishPDF();
    }
	
    
	/**
	 * File to 64bit Str
	 * 
	 * @param file
	 * @return
	 */
	public static String fileToBase64Str(File file) {
		byte[] data = null;
		InputStream inputStream = null;
		if (file != null) {
			try {
				inputStream = new FileInputStream(file);
				data = new byte[inputStream.available()];
				inputStream.read(data);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return Base64.encodeBase64String(data);
		}
		return null;
	}
}

 

templateFCss.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        body{
            font-family:SimHei;
        }
        .color{
            color: green;
        }
        .pos{
            position:absolute;
            left:200px;
            top:5px;
            width: 200px;
            font-size: 10px;
        }
         @media print {
            div.header-right {
                display: block;
                position: running(header-right);
            }
        }
         @page {
            size: 8.5in 11in;

            @top-right {
                content: element(header-right)
            };

            /*@bottom-center {
                content : "Page " counter(page) " of " counter(pages);
            };	 */
            @bottom-center {
                content: element(footer)
            }
        }
        
        #footer {
            position: running(footer);
        }
            
        #pages:before {
            content: counter(page);
        }

        #pages:after {
            content: counter(pages);
        }
        
    </style>
</head>
<body>

  <div id="footer">
        <div style="text-align: center; width: 100%;font-size: 15px;">Page <span id="pages"> of </span></div>
    </div>
	<div class="page">
		<div class="color">你好,${name}222</div>
		<img src="data:${fileType};base64,${file64Str}" width="600px" />
	</div>

</body>
</html>

效果,加上ccs3,就可以有分頁的效果了

 

是不是很棒

 

 

PS:上次有同學分頁有些東西會被隔開怎麼辦

CCS可以幫到你page-break-inside:avoid;這個是可以避免分頁的

測試template

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        body{
            font-family:SimHei;
        }
        .color{
            color: green;
        }
        .pos{
            position:absolute;
            left:200px;
            top:5px;
            width: 200px;
            font-size: 10px;
        }
         @media print {
            div.header-right {
                display: block;
                position: running(header-right);
            }
            
           img{page-break-inside:avoid;}
           table{page-break-inside:avoid;}
        }
         @page {
            size: 8.5in 11in;

            @top-right {
                content: element(header-right)
            };

            /*@bottom-center {
                content : "Page " counter(page) " of " counter(pages);
            };	 */
            @bottom-center {
                content: element(footer)
            }
        }
        
        #footer {
            position: running(footer);
        }
            
        #pages:before {
            content: counter(page);
        }

        #pages:after {
            content: counter(pages);
        }
        
    </style>
</head>
<body>

  <div id="footer">
        <div style="text-align: center; width: 100%;font-size: 15px;">Page <span id="pages"> of </span></div>
    </div>
	<div class="page">
		<div class="color">你好,${name}222</div>
		<img src="data:${fileType};base64,${file64Str}" width="600px" />
		<table border="1">
			<tr>
				<th>Month</th>
				<th>Savings</th>			
			</tr>
			<tr>
				<td>January</td>
				<td>$100</td>
			</tr>
			<tr>
				<td>January</td>
				<td>$100</td>
			</tr>
			<tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr><tr>
				<td>January</td>
				<td>$100</td>
			</tr>
		</table>
	</div>


</body>
</html>

效果

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章