将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
上一篇:你的数字脚印,很难抹去
下一篇:ECS邮箱SMTP连接问题解决
Copyright ©2017-2024 uzen.zone
湘ICP备17013178号-3