JAVA-wkhtmltopdf由HTML页面转pdf

wkhtmltopdf简介

wkhtmltopdf是可以直接把任何一个可以在浏览器中网页直接转换成一个pdf。它不是一个工具类,
而是需要安装在服务器上的一个软件。通过调用CMD命令来执行软件。
具体详情:
官网:https://wkhtmltopdf.org.

wkhtmltopdf的优点和缺点

优点:
1.快速简单
2.支持大量的定制, 包括页头页脚, 页码, 目录等等
缺点:
1.需要在服务器上进行安装服务
2.适用于静态页面
3.表格需要特殊处理
4.eachart图表会出现问题。(eacharts可以使用图片来解决)

下载地址

https://wkhtmltopdf.org/downloads.html.
(太慢的话可以从我这下载64位)
链接:https://pan.baidu.com/s/1c95zFrulcfOYctvnfNRDvw
提取码:q0gw

安装步骤

1.双击安装包
在这里插入图片描述
2.安装完成之后重启电脑(可以记录下来安装路径,需要配置环境变量)

在这里插入图片描述
3.配置环境变量
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
4.测试是否安装成功打开安装的目录在此处 (shift +鼠标右键)点击打开PowerShell窗口
输入wkhtmltopdf http://www.baidu.com/ E:test.pdf(注意中间有空格哈)
在这里插入图片描述
注意:Windows下是 wkhtmltopdf 其他环境下需要改变

CMD命令测试

wkhtmltopdf http://www.baidu.com/ E:test.pdf

项目实例(Java )

此处是由数据生成Html 然后再生成的pdf 。其中包括页眉,封面,公共的头部,背景图片,主体数据(分页)等等

// An highlighted block
/**
	 * 	导出pdf文件(数据整理)
	 * @param request
	 * @return
	 */
	public Message exportHtmlToPDF(HttpServletRequest request) {
		Message m = new Message();
		/**
		 * 	报告模板主体部分静态页面的生成
		 */
		//获取数据
		HashMap<String, Object> reportMap =  getReportInfo(request);//此处是动态获取的数据先生成的Html
		//获取随机生成的文件地址
		String pathMemberReportHtml = report_base_Url+report_base_pdfFile_url+PdfToolUtils.getUUID()+".html";
		//生成静态页面
		FreemarkerFactory.getInstance().writerFile(reportMap,pathMemberReportHtml,pathMemberReportTem);
		//校验页面是否生成
		if(!PdfToolUtils.isExcite(pathMemberReportHtml)) {//判断即将生成pdf的html页面是否存在
			m.setErrorInfo("报告生成失败,页面不存在");
			m.setErrorNo(2);
			return m;
		}
		
		/**
		 * 	用户个人报告模板页面页眉部分静态页面的生成
		 */
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String nowTime = sdf.format(new Date());
		//获取年月日时间搓
		String replace = nowTime.replace("-", "");
		//获取六位随机数
		int random = PdfToolUtils.getRandom();
		String reportNum =replace+random;
		//页眉 (主要是用户基本数据)
		//获取数据
		HashMap<String, Object> memberMap = getMemberInfo(memberChildId,hcPackageId);
		memberMap.put("reportNum",reportNum);
		//获取随机生成的文件地址
		String pathHeaderHtml = report_base_Url+report_base_pdfFile_url+PdfToolUtils.getDateRandomUUID()+".html";
		//生成静态页面
		FreemarkerFactory.getInstance().writerFile(memberMap,pathHeaderHtml,pathHeaderTem);
		//校验页面是否生成
		if(!PdfToolUtils.isExcite(pathHeaderHtml)) {//判断即将生成pdf的html页面是否存在
			m.setErrorInfo("报告生成失败,页面不存在");
			m.setErrorNo(2);
			return m;
		}
		
		/**
		 * 	生成首页html
		 */
		//获取首页html的信息
		// 1.生成首页地址
		String coverHtml = report_base_Url+report_base_pdfFile_url+PdfToolUtils.getDateRandomUUID()+".html";
		HashMap<String, Object> coverMap = new HashMap<String, Object>();
			SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String nowTime2 = sdf2.format(new Date());
			coverMap.put("reportCreateDate",nowTime2);
			//首页图片
			coverMap.put("iconImg",iconImg);
			FreemarkerFactory.getInstance().writerFile(coverMap,coverHtml,pathCoverTem);
			//校验页面是否生成
			if(!PdfToolUtils.isExcite(coverHtml)) {//判断即将生成pdf的html页面是否存在
				m.setErrorInfo("报告生成失败,页面不存在");
				m.setErrorNo(2);
				return m;
			}
	
		//生成主体pdf
		String memberPdfPath = report_base_Url+report_base_pdfFile_url + PdfToolUtils.getDateRandomUUID() +".pdf";
		String  pathfooterHtml = report_base_Url+report_base_ftl_url+pathFootHtml;
		log.info("页脚地址:============================"+pathfooterHtml);
		String pdfCmdStr = 	HtmlToPdfUtils.toPdfTool+" --margin-top 60mm --header-html "+pathHeaderHtml+" --header-spacing 10 --footer-center [page]/[topage] "+pathMemberReportHtml;
		log.info("主体cmd命令:============================"+pdfCmdStr+" "+memberPdfPath);
		HtmlToPdfUtils.convert(memberPdfPath,pdfCmdStr);
		//校验主体pdf文件是否已经生成
		if(!PdfToolUtils.isExcite(memberPdfPath)) {
			m.setErrorInfo("文件生成失败");
			m.setErrorNo(2);
		}
		//生成首页pdf coverHtml
		//要生成的首页pdf地址
		String coverPdfPath = report_base_Url+report_base_pdfFile_url + PdfToolUtils.getDateRandomUUID() +".pdf";
		//cmd 命令
		String coverPdfCmdStr = HtmlToPdfUtils.toPdfTool+"  --margin-top 30mm "+coverHtml;
		log.info("首页cmd命令:============================"+coverPdfCmdStr+" "+coverPdfPath);
		HtmlToPdfUtils.convert(coverPdfPath,coverPdfCmdStr);
		//校验主体pdf文件是否已经生成
		if(!PdfToolUtils.isExcite(coverPdfPath)) {
			m.setErrorInfo("文件生成失败");
			m.setErrorNo(2);
			return m;
		}
		//合并首页与主体pdf文件
		//pdf文件路径集合,添加顺序为拼接顺序
		ArrayList<String> urlList = new ArrayList<String>();
		//首页pdf地址
		urlList.add(coverPdfPath);
		//主体pdf地址
		urlList.add(memberPdfPath);
		//拼接后的pdf地址 
		String mergeToPdfPath = report_base_Url+report_base_pdfFile_url + PdfToolUtils.getDateRandomUUID() +".pdf";
		PdfToolUtils.mergePdf(urlList,mergeToPdfPath);
		//校验主体pdf文件是否已经生成
		if(!PdfToolUtils.isExcite(mergeToPdfPath)) {
			m.setErrorInfo("文件生成失败(拼接失败)");
			m.setErrorNo(2);
			return m;
		}
		// 最终生成pdf的地址
		String pdfParh = report_base_Url+report_base_pdfFile_url+PdfToolUtils.getDateRandomUUID()+".pdf";
		//处理已生成的pdf文件(添加背景图)
		//添加背景图
		String path = PdfToolUtils.setBackgroundImg(mergeToPdfPath,pdfParh, report_base_Url+pdfBackgroundImgPath);
		if(!PdfToolUtils.isExcite(path)) {
			m.setErrorInfo("报告生成异常");
			m.setErrorNo(2);
			return m;
		}
		
		/**
		 * 	删除生成的无用页面
		 */
		//删除生成的页眉静态文件
		PdfToolUtils.delFile(pathHeaderHtml);
		//删除生成的用户报告主体静态文件
		PdfToolUtils.delFile(pathMemberReportHtml);
		//删除不含背景图的用户报告——pdf文件
		PdfToolUtils.delFile(memberPdfPath);
		//删除封面
		PdfToolUtils.delFile(coverHtml);
		//删除首页pdf文件
		PdfToolUtils.delFile(coverPdfPath);
		//此处省略数据库操作
		m.setData(path);
		m.setErrorNo(1);
		return m;
	}

	

工具类

package com.cloud.template.utils;
import java.io.File;
import java.util.HashMap;
import com.itextpdf.text.log.SysoLogger;
public class HtmlToPdfUtils {
	/**
	 * wkhtmltopdf命令地址
	 * wkhtmltopdf在windows系统中的路径
	 */
	//服务器 本地修改成--wkhtmltopdf 
	public static final String toPdfTool = " /home/.............../wkhtmltopdf";
    /**
     * html转pdf
     * @param map 主要包含各种业务需要路径
     * @return 转换成功返回true
     */
    public static boolean  convert(String pdfPath,String pdfCmdStr){
        File file = new File(pdfPath);
        File parent = file.getParentFile();
        //如果pdf保存路径不存在,则创建路径
        if(!parent.exists()){
            parent.mkdirs();
        }
        StringBuilder cmd = new StringBuilder();
        cmd.append(pdfCmdStr);
        cmd.append(" ");
        cmd.append(pdfPath);
//        
        boolean result = true;
        HtmlToPdfInterceptor error = null;
        HtmlToPdfInterceptor output = null;
        Process proc = null;
        try{
        	proc = Runtime.getRuntime().exec(cmd.toString());
            error = new HtmlToPdfInterceptor(proc.getErrorStream());
            output = new HtmlToPdfInterceptor(proc.getInputStream());
            error.start();
            output.start();
            proc.waitFor();
            System.err.println("生成成功");
        }catch(Exception e){
            result = false;
            System.err.println("生成失败");
            e.printStackTrace();
        }
        return result;
    }

}

package com.cloud.template.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class HtmlToPdfInterceptor extends Thread {
    private InputStream is;
    public HtmlToPdfInterceptor(InputStream is){
        this.is = is;
    }
    public void run(){
        try{
            InputStreamReader isr = new InputStreamReader(is, "utf-8");
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(line.toString()); //输出内容
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
package com.cloud.template.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;

/**
 * 开发报告模板所需工具类集
 */
public class PdfToolUtils {
	/**
	 * 下载pdf文件
	 * @param pdfPath 
	 */
	public static void downloadPdf(HttpServletResponse response,HttpServletRequest request, String pdfPath) {
		File file = new File(pdfPath);
		String filename = "个人报告.pdf";
		if (file.exists()) {
            OutputStream out = null;
            FileInputStream in = null;
            try {
                // 1.读取要下载的内容
                in = new FileInputStream(file);

                // 2. 告诉浏览器下载的方式以及一些设置
                // 解决文件名乱码问题,获取浏览器类型,转换对应文件名编码格式,IE要求文件名必须是utf-8, firefo要求是iso-8859-1编码
                String agent = request.getHeader("user-agent");
                if (agent.contains("FireFox")) {
                    filename = new String(filename.getBytes("UTF-8"), "iso-8859-1");
                } else {
                    filename = URLEncoder.encode(filename, "UTF-8");
                }
                // 设置下载文件的mineType,告诉浏览器下载文件类型
                String mineType = request.getServletContext().getMimeType(filename);
                response.setContentType(mineType);
                // 设置一个响应头,无论是否被浏览器解析,都下载
                response.setHeader("Content-disposition", "attachment; filename=" + filename);
                // 将要下载的文件内容通过输出流写到浏览器
                out = response.getOutputStream();
                int len = 0;
                byte[] buffer = new byte[1024];
                while ((len = in.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                	if (out != null) {out.close();}
				} catch (IOException e) {
					e.printStackTrace();
				}
            
                try {
                	if (in != null) {in.close();}
				} catch (IOException e) {
					e.printStackTrace();
				}
            }
        }
	}
	
	/**
	 * 	为pdf添加背景图
	 * @return
	 */
	public static String setBackgroundImg(String pdfPath,String newPdfPath,String imgPath) {
		try {
			PdfReader reader = new PdfReader(pdfPath);
			FileOutputStream fileOutputStream = new FileOutputStream(newPdfPath);
			PdfStamper stamp = new PdfStamper(reader, fileOutputStream);
			Image img = Image.getInstance(imgPath);
			
			//设置页面大小
			img.scaleAbsolute(PageSize.A4);
			img.setAbsolutePosition(0f, 0f);
			
			//获取该文件总页数
			int pageNum = reader.getNumberOfPages();
			//给pdf文件每页添加背景图
			for (int i = 0; i < pageNum; i++) {
				PdfContentByte under = stamp.getUnderContent(i+1);
				under.addImage(img);
			}
			//关闭工具
			stamp.close();
			fileOutputStream.close();
			reader.close();
		} catch (IOException e) {
			
			e.printStackTrace();
		}catch (DocumentException e) {
			
			e.printStackTrace();
		}
		return newPdfPath;
	}
	
	/**
	 * 	合并多个pdf文件
	 */
	public static void mergePdf(List<String> fileList, String savepath) {
        Document document = null;
        try {
            document = new Document(new PdfReader(fileList.get(0)).getPageSize(1));
            PdfCopy copy = new PdfCopy(document, new FileOutputStream(savepath));
            document.open();
            for (int i = 0; i < fileList.size(); i++) {
                PdfReader reader = new PdfReader(fileList.get(i));
                int n = reader.getNumberOfPages();// 获得总页码
                for (int j = 1; j <= n; j++) {
                    document.newPage();
                    PdfImportedPage page = copy.getImportedPage(reader, j);// 从当前Pdf,获取第j页
                    copy.addPage(page);
                }
                System.out.println(i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            if (document != null) {
                document.close();
            }
            System.out.println("finish " + new Date());
        }
    }
	
	/**
     * 判断文件是否已经存在
     * @return
     */
    public static boolean isExcite(String filePath) {
        File file = new File(filePath);
        // 如果文件夹不存在
        if (!file.exists() && !file.isDirectory()) {
            return false;
        } else {
            return true;
        }
    }
    
    /**
     * 	根据路径删除文件或者是文件夹
     * @param file
     * @return
     */
    public static void delFile(String filePath) {
    	File file = new File(filePath);
        if (!file.exists()) {
        }

        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File f : files) {
            	String path = f.getPath();
                delFile(path);
            }
        }
        file.delete();
    }
    public static void main(String[] args) {
    	String chineseDate = getChineseDate("2019-10-22 10:46:27");
    	System.out.println(chineseDate);
	}


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值