文章信息

使用wkhtmltopdf转换需要登录的页面

发布时间:『 2018-06-16 09:55』  文章类别:技术开发  阅读(6055) 评论(2)

    将HTML转成PDF的方案有很多,比如ntko office、itext,这两种都需要自己写模版,表单要是改变了还得去改模板,还是比较麻烦的。使用wkhtmltopdf是一种不错的选择,wkhtmltopdf是一个使用webkit网页渲染引擎开发的用来将 html转成 pdf的工具,可以跟多种脚本语言进行集成来转换文档,官网地址:https://wkhtmltopdf.org/,wkhtmltopdf还有个兄弟wkhtmltoimage,他们共同组成wkthmltox。

    使用方法:①官网下载工具,安装;②配置环境变量,在path中添加wkhtmltopdf的安装路径;③在shell中查看版本,运行wkhtmltopdf --version;④快速体验,shell中运行wkhtmltopdf https://www.zeal.name/blog/articles/101.html zeal_name.pdf;⑤选项使用帮助,shell中运行wkhtmltopdf -H。wkhtmltopdf常使用的选项如--header-html,--footer-html,--page-size,--orientation可以去了解一下。

    wkhtmltopdf由于运行在服务端,生成需要登录认证的页面时,由于服务器上没有会话,导致最终生成的是登录页面,只能将这个页面开放为匿名访问,这样会导致应用不安全。

    其实,wkhtmltopdf是可以设置cookie的,我们只要将当前会话的cookies注入到shell中再去运行就能完美解决服务器上没有会话的问题。wkhtmltopdf的这个选项是--cookie,且支持多个--cookie选项。使用方式cmd/shell示例:

wkhtmltopdf --cookie JSESSIONID AC78C1D22FE99DCFB8CEFD5D9AB78B75 --cookie rememberMe deleteMe https://www.zeal.name/blog/articles/101.html zeal_name2.pdf

    至于java如何调用shell两行核心代码也在这里简单提一下:

Process ps = Runtime.getRuntime().exec(shell);
ps.waitFor();

    以下代码是工具类的完整举例实现,前提是需安装好wktmltopdf并配置好环境变量,仅供参考:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.Cookie;

/**
 * 将HTML转PDF工具类
 * 
 * @author zeal.name
 * @date 2020-01-09
 */
public class HtmlToPdfUtil {

	public static String oSname = System.getProperty("os.name").toLowerCase();// 当前系统
	// 保存进程的输入流信息
	private static List<String> stdoutList = new ArrayList<String>();
	// 保存进程的错误流信息
	private static List<String> erroroutList = new ArrayList<String>();

	public List<String> getStdoutList() {
		return stdoutList;
	}

	public List<String> getErroroutList() {
		return erroroutList;
	}

	/**
	 * @param filePathName pdf保存路径(带文件名)
	 * @param cookies      需注入的cookie数组
	 * @param sourceUrl    源URL
	 */
	public static void exec(String filePathName, Cookie[] cookies, String sourceUrl) {
		stdoutList.clear();
		erroroutList.clear();
		StringBuffer sb = new StringBuffer();
		for (Cookie cookie : cookies) {
			String value = cookie.getValue();
			sb.append(" --cookie " + cookie.getName() + " "
					+ (value == null || "".equals(value.trim()) ? "null" : value));
		}
		String shellStr = "wkhtmltopdf --page-size A4 \"" + sourceUrl + "\" " + filePathName;

		String[] shell = null;
		// 根据系统使用相应的指令
		if (oSname.indexOf("linux") >= 0) {
			shell = new String[] { "sh", "-c", shellStr };
		} else if (oSname.indexOf("windows") >= 0) {
			shell = new String[] { "cmd", "/C", shellStr };
		}
		try {

			Process ps = Runtime.getRuntime().exec(shell);
			ThreadUtil stdoutUtil = new ThreadUtil(ps.getInputStream(), stdoutList);
			ThreadUtil erroroutUtil = new ThreadUtil(ps.getErrorStream(), erroroutList);
			// 启动线程读取缓冲区数据
			stdoutUtil.start();
			erroroutUtil.start();
			ps.waitFor(); // 等待进程结束后才会继续下一步
			if (ps.exitValue() != 0) {// 执行完毕的返回值
				System.err.println("异常信息:html转pdf执行失败,请检查服务器wkhtmltopdf是否已正确安装配置");
			}
			ps.destroy(); // 销毁子进程
			ps = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

class ThreadUtil implements Runnable {
	// 设置读取的字符编码
	private String character = "GB2312";
	private List<String> list;
	private InputStream inputStream;

	public ThreadUtil(InputStream inputStream, List<String> list) {
		this.inputStream = inputStream;
		this.list = list;
	}

	public void start() {
		Thread thread = new Thread(this);
		thread.setDaemon(true);// 将其设置为守护线程
		thread.start();
	}

	public void run() {
		BufferedReader br = null;
		try {
			br = new BufferedReader(new InputStreamReader(inputStream, character));
			String line = null;
			while ((line = br.readLine()) != null) {
				if (line != null) {
					list.add(line);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				// 释放资源
				inputStream.close();
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

    最后还有几点注意事项,如果你脚本中的URL地址带有&符号,建议用英文模式下的双引号将地址包起来,以确保脚本顺利执行。如果你的系统部署在linux服务器上,wkhtmltopdf生成的PDF可能中文显示空白或者方格,则需要安装simsun.ttc字体到/usr/share/fonts/目录下。如果你的系统部署在linux服务器上,需要对java环境进行配置Headless模式。Headless模式是系统的一种配置模式,在该模式下,系统缺少了显示设备、键盘或鼠标。服务器往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,以提供给客户端(如浏览器所在的配有相关的显示设备、键盘和鼠标的主机)。设置Headless模式就是告诉java,现在不要调用硬件帮忙了,需依靠系统的计算能力模拟出这些特性来。

    配置方式常用有两种:①配置应用中System属性:System.setProperty("java.awt.headless", "true");②系统中配置java环境选项:java -Djava.awt.headless=true。更多关于Headless模式的说明请参考官网文章:Using Headless Mode in the Java SE Platform

关键字:  wkhtmltopdf  option  cookie  html  pdf  java配置
评论信息
1楼    116.236.232.250:大佬能加个微信吗      [ 2020-01-11 05:58 ]
2楼    119.39.19.171:微信在关于小主栏目里,添加微信请表明身份哦      [ 2020-01-19 14:47 ]
发表评论
验证码: 
当前时间
小主信息

愿历尽千帆,归来仍少年。
3D标签云

Anything in here will be replaced on browsers that support the canvas element

友情链接

Copyright ©2017-2024 uzen.zone
湘ICP备17013178号-3