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);
}
}