使用freemMarker模板和wkhtmltopdf工具生成pdf

前提:

在项目需求中会涉及到生成的PDF附件,刚开始使用的iText java类库生成pdf,但面对样式变化较多的情况下itext就显得有点复杂,作者在权衡之后选择使用html模板啦生成样式多变的PDF格式。

  • 作者选择的工具自己步骤为:

1,使用freemarker的生成HTML模板。

  • FreeMarker的是一个模板生成引擎,可以理解为前后端完全分离的JSP,通过页面的表达式和后台设定的值生成动态的模板,这里用它来生成HTML文件。
  • Freemarker的模板:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户信息</title>
<!-- 新 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet"
    href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css" />
</head>
<body style="font-family:'Courier New'">
    <#--这里是一段注释,这里是单个属性的展示-->
    <h3 class="text-center">这是用户${username}的信息页!</h3>
    <#--这里是一段注释,下面是转义字符的应用-->
    <a>${"这是一段字符串,里面有转义字符\"双引号\""}</a></br>
    <#--这里是一段注释,下面是各种特殊字符原样输出-->    
    <a>${r"这是一段字符,带有各种>转义字符${foo}fsf"}</a></br>
    <#--自定义变量-->
    <#assign x=11>
    <a>x=${x}</a></br>
    <a>x/2=${x/2}</a></br>
    <a>x/2=${(x/2)?int}(转为整形)</a></br>
    <a>x+“3”=${x+"3"}</a></br>
    <#--这里是一段注释,下面是一个表格,数据来源list,包含时间格式的显示-->
    <div class="col-md-6 column">
        <table class="table table-bordered">
            <tr>
                <th>has_next:下标:姓名</th>
                <th>学生的密码</th>                                
                <th>学生的年龄</th>                                                
                <th>学生的地址</th>
                <th>学生的生日</th>                               
           </tr>
           <#list userList as user>
	            <tr>
	                <td>${userList?is_hash?string("true","false")}:${user_index}:${user.username}</td>
	                <td>${user.password}</td>
	                <td>${user.age}</td>
	                <td>${user.address}</td>
	                <#if user_index==1>
		            <td>date:${user.birthday?date}</td>
	                <#elseif user_index==2>
		            <td>datetime:${user.birthday?datetime}</td>
	                <#elseif user_index==3>
		            <td>time:${user.birthday?time}</td>
	                <#else>
		            <td>time:${user.birthday?time}</td>
	                </#if>
	            </tr>
            </#list>
        </table>
    </div>
</body>
</html>
  • FreeMarker的生成HTML文件:调用geneFileStr方法
package com.netsmart.util;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class FreeMarkerToHtmlUtil {
	 private static FreeMarkerToHtmlUtil instance;
	    private Configuration config;
	    
//	    String templatePath = "/freeMarker/";
	    String templatePath = ReadProperties.getValue("template.properties","templatePath");

	    /**
	     * instance FreeMarkerUtil
	     * @return
	     */
	    public static FreeMarkerToHtmlUtil instance() {
	        if (instance == null) {
	            instance = new FreeMarkerToHtmlUtil();
	        }
	        return instance;
	    }
	    
	    /**
	     * instance Configuration
	     * @param request
	     */
	    private void configInstance(HttpServletRequest request) {
	        if (this.config == null) {
	            this.config = new Configuration();
	            this.config.setServletContextForTemplateLoading(request.getSession().getServletContext(),templatePath);
	        }
	    }
	    
	    /**
	     * 利用freemarker模板生成html文件
	     * @param request
	     * @param templateFileName 模板文件
	     * @param propMap 模板中所需数据
	     * @param htmlPath 存储的html文件名
	     * @return 生成html文件的绝对路径
	     */
	    public String geneFileStr(HttpServletRequest request,String templateFileName, String htmlPath,Map<String, Object> propMap) {
	        configInstance(request);
	        StringWriter out = new StringWriter();
	        Template tmp;
	        htmlPath =ReadProperties.getValue("template.properties","htmlLocation")+"/"+htmlPath;
	        File htmlFile = new File(htmlPath);
	        try {
	        	htmlPath = htmlFile.getCanonicalPath();
	        	// 定义输出流,注意必须指定编码
	        	Writer writer = new BufferedWriter(
	        			new OutputStreamWriter(new FileOutputStream(htmlFile), "UTF-8"));
	        	// 生成模版
	            tmp = this.config.getTemplate(templateFileName,"UTF-8");
	            tmp.setEncoding("UTF-8");
	            tmp.process(propMap, writer);
	        } catch (IOException e) {
	            e.printStackTrace();
	        } catch (TemplateException e) {
	            e.printStackTrace();
	        }
	        return htmlPath;
	    }
}
  • 然后就可以生成HTML文件,下图是文件效果图:

2,将生成好的HTML文件利用wkhtmltopdf工具生成PDF文件,这里可以利用的java执行DOS命令来生成。

  • wkhtmltopdf是一款需要下载安装的用来生成PDF的软件,可以在https://wkhtmltopdf.org/选择合适版本下载安装。
  • 安装完成之后,使用dos命令生成pdf:

  • 第一个参数为wkhtmltopdf安装目录+“/bin/wkhtmltopdf”,第二个参数为html网址(或本地html路径),第三个为生成pdf全路径,下图为生成效果:

  • 可以看出页面的样式也被很好的保留下来。上一步我们已经使用freeMarker引擎生成了html文件,只需要将dos命令中html的参数修改为生成html的路径,就可以生成一份格式良好的pdf了!!!
  • 这里我们使用java调用dos命令,下面是调用dos命令的代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class OperationDOS {

	public static int createPdf(String htmlPath,String pdfName){
        //wkhtmltopdf的安装路径+"/bin"
		String appPath = ReadProperties.getValue("template.properties", "appPath");
        //生成的pdf存储路径,可自己设置
		String pdfPath = ReadProperties.getValue("template.properties", "pdfPath");
		String dosCommand = appPath + "wkhtmltopdf "+htmlPath+ " " + pdfPath + pdfName;
		int exitVal = 0;
		try {
			Process pr = Runtime.getRuntime().exec(dosCommand);
			BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream(), Charset.forName("GBK")));
			String line = null;
			StringBuilder sb = new StringBuilder(); 
			while ((line = input.readLine()) != null) { 
			sb.append(line + "\n"); 
			} 
			System.out.println(sb.toString());
			exitVal = pr.waitFor();
			System.out.println("Exited with error code " + exitVal);

		} catch (Exception e) {
			System.out.println(e.toString());
			e.printStackTrace();
		}
		
		return exitVal;
	}
	public static void main(String[] args) {
		String dosCommand = "ping www.baidu.com";
		int exitVal = 0;
		try {
			Process pr = Runtime.getRuntime().exec(dosCommand);
			BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream(), Charset.forName("GBK")));
			String line = null;
			StringBuilder sb = new StringBuilder(); 
			while ((line = input.readLine()) != null) { 
			sb.append(line + "\n"); 
			} 
			System.out.println(sb.toString());
			exitVal = pr.waitFor();
			System.out.println("Exited with error code " + exitVal);

		} catch (Exception e) {
			System.out.println(e.toString());
			e.printStackTrace();
		}
		
	}
	
}

这样,一份pdf就可以完美实现了,笔者水平有限,如有错误还望大家多多指教!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值