通过java调用系统中的wkhtmltopdf

通过java调用系统中的wkhtmltopdf

希望达到脱离浏览器将页面导成 pdf 的效果, 于是利用 wkhtmltopdf 的将 urlpdf 的能力实现
利用 java 代码触发 wkhtmltopdf

注意事项

有几点东西要注意一下

  1. 中文字体问题, 大多数 linux 系统是默认不带中文字体的, 需要自己手动安装一下
  2. 这个操作相对还是比较耗时的(特别是网络开销), 如果并发量比较大需要关注下性能问题
  3. 剩下就不细讲了, 看下面的源码应该都明白了

参数说明

命令格式

wkhtmltopdf [OPTIONS]... <input file> [More input files] <output file>

常规选项

  • --allow <path>: 允许加载从指定的文件夹中的文件或文件(可重复)
  • --book: 设置一会打印一本书的时候,通常设置的选项
  • --collate: 打印多份副本时整理
  • --cookie <name> <value>: 设置一个额外的cookie(可重复)
  • --cookie-jar <path>: 读取和写入的Cookie,并在提供的cookie jar文件
  • --copies <number>: 复印打印成pdf文件数(默认为1)
  • --cover* <url>: 使用HTML文件作为封面。它会带页眉和页脚的TOC之前插入
  • --custom-header <name> <value>: 设置一个附加的HTTP头(可重复)
  • --debug-javascript: 显示的javascript调试输出
  • --default-header: 添加一个缺省的头部,与页面的左边的名称,页面数到右边,例如:–header-left '[webpage]' --header-right '[page]/[toPage]' --header-line
  • --disable-external-links: 禁止生成链接到远程网页
  • --disable-internal-links: 禁止使用本地链接
  • `–disable-javascript 禁止让网页执行JavaScript
  • --disable-pdf-compression: 禁止在PDF对象使用无损压缩
  • --disable-smart-shrinking: 禁止使用WebKit的智能战略收缩,使像素/ DPI比没有不变
  • --disallow-local-file-access: 禁止允许转换的本地文件读取其他本地文件,除非explecitily允许用 --allow
  • --dpi <dpi>: 显式更改DPI(这对基于X11的系统没有任何影响)
  • --enable-plugins: 启用已安装的插件(如Flash
  • --encoding <encoding>: 设置默认的文字编码
  • --extended-help: 显示更广泛的帮助,详细介绍了不常见的命令开关
  • --forms: 打开HTML表单字段转换为PDF表单域
  • --grayscale: PDF格式将在灰阶产生
  • --help: Display help
  • --htmldoc: 输出程序HTML帮助
  • --ignore-load-errors: 忽略claimes加载过程中已经遇到了一个错误页面
  • --lowquality: 产生低品质的PDF/ PS。有用缩小结果文档的空间
  • --manpage: 输出程序手册页
  • --margin-bottom <unitreal>: 设置页面下边距 (default 10mm)
  • --margin-left <unitreal>: 将左边页边距 (default 10mm)
  • --margin-right <unitreal>: 设置页面右边距 (default 10mm)
  • --margin-top <unitreal>: 设置页面上边距 (default 10mm)
  • --minimum-font-size <int>: 最小字体大小 (default 5)
  • --no-background: 不打印背景
  • --orientation <orientation>: 设置方向为横向或纵向
  • --page-height <unitreal>: 页面高度 (default unit millimeter)
  • --page-offset* <offset>: 设置起始页码 (default 1)
  • --page-size <size>: 设置纸张大小: A4, Letter, etc.
  • --page-width <unitreal>: 页面宽度 (default unit millimeter)
  • --password <password>: HTTP验证密码
  • --post <name> <value>: Add an additional post field (repeatable)
  • --post-file <name> <path>: Post an aditional file (repeatable)
  • --print-media-type: 使用的打印介质类型,而不是屏幕
  • --proxy <proxy>: 使用代理
  • --quiet: Be less verbose
  • --read-args-from-stdin: 读取标准输入的命令行参数
  • --readme: 输出程序自述
  • --redirect-delay <msec>: 等待几毫秒为JS-重定向(default 200)
  • --replace* <name> <value>: 替换名称,值的页眉和页脚(可重复)
  • --stop-slow-scripts: 停止运行缓慢的JavaScripts
  • --title <text>: 生成的PDF文件的标题(第一个文档的标题使用,如果没有指定)
  • --toc: 插入的内容的表中的文件的开头
  • --use-xserver: 使用X服务器(一些插件和其他的东西没有X11可能无法正常工作)
  • --user-style-sheet <url>: 指定用户的样式表,加载在每一页中
  • --username <username>: HTTP认证的用户名
  • --version: 输出版本信息退出
  • --zoom <float>: 使用这个缩放因子 (default 1)

页眉和页脚选项

  • --header-center** <text>: (设置在中心位置的页眉内容)
  • --header-font-name* <name>: (default Arial) (设置页眉的字体名称)
  • --header-font-size* <size>: (设置页眉的字体大小)
  • --header-html <url>: (添加一个HTML页眉,后面是网址)
  • --header-left <text>: (左对齐的页眉文本)
  • --header-line: (显示一条线在页眉下)
  • --header-right* <text>: (右对齐页眉文本)
  • --header-spacing: <real>: (设置页眉和内容的距离,默认0)
  • --footer-center: <text>: (设置在中心位置的页脚内容)
  • --footer-font-name* <name>: (设置页脚的字体名称)
  • --footer-font-size* <size>: (设置页脚的字体大小default 11)
  • --footer-html <url>: (添加一个HTML页脚,后面是网址)
  • --footer-left <text>: (左对齐的页脚文本)
  • --footer-line: 显示一条线在页脚内容上)
  • --footer-right <text>: (右对齐页脚文本)
  • --footer-spacing <real>: (设置页脚和内容的距离)

###表内容选项中

  • --toc-depth <level>: Set the depth of the toc (default 3)
  • --toc-disable-back-links: Do not link from section header to toc
  • --toc-disable-links: Do not link from toc to sections
  • --toc-font-name* <name>: Set the font used for the toc (default Arial)
  • --toc-header-font-name* <name>: The font of the toc header (if unset use --toc-font-name)
  • --toc-header-font-size* <size>: The font size of the toc header (default 15)
  • --toc-header-text* <text>: The header text of the toc (default Table Of Contents)
  • --toc-l1-font-size* <size>: Set the font size on level 1 of the toc (default 12)
  • --toc-l1-indentation* <num>: Set indentation on level 1 of the toc (default 0)
  • --toc-l2-font-size* <size>: Set the font size on level 2 of the toc (default 10)
  • --toc-l2-indentation* <num>: Set indentation on level 2 of the toc (default 20)
  • --toc-l3-font-size* <size>: Set the font size on level 3 of the toc (default 8)
  • --toc-l3-indentation* <num>: Set indentation on level 3 of the toc (default 40)
  • --toc-l4-font-size* <size>: Set the font size on level 4 of the toc (default 6)
  • --toc-l4-indentation* <num>: Set indentation on level 4 of the toc (default 60)
  • --toc-l5-font-size* <size>: Set the font size on level 5 of the toc (default 4)
  • --toc-l5-indentation* <num>: Set indentation on level 5 of the toc (default 80)
  • --toc-l6-font-size* <size>: Set the font size on level 6 of the toc (default 2)
  • --toc-l6-indentation* <num>: Set indentation on level 6 of the toc (default 100)
  • --toc-l7-font-size* <size>: Set the font size on level 7 of the toc (default 0)
  • --toc-l7-indentation* <num>: Set indentation on level 7 of the toc (default 120)
  • --toc-no-dots: Do not use dots, in the toc
    轮廓选项
  • -dump-outline <file>: 转储目录到一个文件
  • --outline: 显示目录(文章中h1,h2来定)
  • --outline-depth <level>: 设置目录的深度(默认为4)
    页脚和页眉
  • [page]: 由当前正在打印的页的数目代替
  • [frompage]: 由要打印的第一页的数量取代
  • [topage]: 由最后一页要打印的数量取代
  • [webpage]: 通过正在打印的页面的URL替换
  • [section]: 由当前节的名称替换
  • [subsection]: 由当前小节的名称替换
  • [date]: 由当前日期系统的本地格式取代
  • [time]: 由当前时间,系统的本地格式取代

页脚和页眉

  • [page]: 由当前正在打印的页的数目代替
  • [frompage]: 由要打印的第一页的数量取代
  • [topage]: 由最后一页要打印的数量取代
  • [webpage]: 通过正在打印的页面的URL替换
  • [section]: 由当前节的名称替换
  • [subsection]: 由当前小节的名称替换
  • [date]: 由当前日期系统的本地格式取代
  • [time]: 由当前时间,系统的本地格式取代

源码分享

/**
 * @Author: WanG
 * @Date: 2019-08-22 13:54
 * @version: v1.0
 * @description: 使用wkhtmltopdf, 来将页面转成pdf
 */
@Slf4j
@Service
public class PDFService {
	
	private Random random = new Random();

	/**
	 * 将传入的页面转pdf, 返回字节数组
	 * 默认自动随机生成文件名字
	 * @author wangq 2019-08-22 16:27
	 * @param url 页面url
	 * @return
	 */
	public byte[] html2pdf(String url) {
		String tmp = System.getProperty("java.io.tmpdir");
		String filename = System.currentTimeMillis() + random.nextInt(1000) + "";
		return doHtml2pdf(url, tmp + "/" + filename);
	}


	private byte[] doHtml2pdf(String src, String dest) {
		String space = " ";
		String wkhtmltopdf = findExecutable();

		if (StringUtils.isEmpty(wkhtmltopdf)) {
			log.error("no wkhtmltopdf found!");
			throw new RuntimeException("html转换pdf出错了");
		}

		File file = new File(dest);
		File parent = file.getParentFile();
		if (!parent.exists()) {
			boolean dirsCreation = parent.mkdirs();
			log.info("create dir for new file,{}", dirsCreation);
		}

		/*
			一些特殊符号
			[page] : 页码
			[data] : 日期(例如:8/22/19)
		 */
		StringBuilder cmd = new StringBuilder();
		cmd.append(findExecutable()).append(space)
				.append(src).append(space)
				.append("--footer-center").append(space).append("[page]").append(space)
				.append("--footer-font-size").append(space).append("14").append(space)
				.append("--disable-smart-shrinking").append(space)
				.append("--load-media-error-handling")
				.append(space).append("ignore").append(space)
				.append("--load-error-handling").append(space).append("ignore").append(space)
				.append("--footer-right").append(space).append("WanG提供技术支持").append(space)
				.append(dest);
		InputStream is = null;

		try {
			String finalCmd = cmd.toString();
			log.info("final cmd:{}", finalCmd);

			Process proc = Runtime.getRuntime().exec(finalCmd);

			new Thread(new ProcessStreamHandler(proc.getInputStream())).start();
			new Thread(new ProcessStreamHandler(proc.getErrorStream())).start();

			proc.waitFor();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			is = new FileInputStream(file);
			byte[] buf = new byte[1024];

			while (is.read(buf, 0, buf.length) != -1) {
				baos.write(buf, 0, buf.length);
			}

			return baos.toByteArray();

		} catch (Exception e) {
			log.error("html转换pdf出错", e);
			throw new RuntimeException("html转换pdf出错了");

		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	/**
	 * 根据当前系统返回 wkhtmltopdf 执行命令
	 * @author wangq 2019-08-22 16:26
	 * @return
	 */
	public String findExecutable() {
		Process p;
		try {
			String osname = System.getProperty("os.name").toLowerCase();
			String cmd = osname.contains("windows") ? "where wkhtmltopdf" : "which wkhtmltopdf";
			p = Runtime.getRuntime().exec(cmd);
			new Thread(new ProcessStreamHandler(p.getErrorStream())).start();
			p.waitFor();
			return IOUtils.toString(p.getInputStream(), Charset.defaultCharset());
		} catch (Exception e) {
			log.error("no wkhtmltopdf found!", e);
		}
		return "";
	}

	private static class ProcessStreamHandler implements Runnable {
		private InputStream is;
		public ProcessStreamHandler(InputStream is) {
			this.is = is;
		}
		@Override
		public void run() {
			BufferedReader reader = null;
			try {
				InputStreamReader isr = new InputStreamReader(is, "utf-8");
				reader = new BufferedReader(isr);
				String line;
				while ((line = reader.readLine()) != null) {
					log.debug(line);
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (reader != null) {
					try {
						reader.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值