java实现html转pdf

java实现将html网页转pdf,如果需求只是将一些简单的html元素转成pdf,那么使用 itext 或者 FlyingSaucer 就可以搞定,但是真正的网页url类型的html涉及到的 html 语法和 css语法实在是太复杂,itext 和 FlyingSaucer 根本没法搞定。

最后发现使用 phantomjs 可以完美将html转换为pdf,大概思路如下:

一、下载phantomjs

https://phantomjs.org/download.html  根据操作系统下载对应的phantomjs版本

二、编写 html2pdf.js

内容如下:

var page = require('webpage').create();
var system = require('system');

// 读取命令行参数,也就是js文件路径。
if (system.args.length === 1) {
  console.log('Usage: phantomjs html2pdf.js    ');
  //这行代码很重要。凡是结束必须调用。否则phantomjs不会停止
  phantom.exit();
}
page.settings.loadImages = true;  //加载图片
page.settings.resourceTimeout = 30000;//超过30秒放弃加载

var address = system.args[1];
// server in windows: width + 'mm', linux: (width * 3.7794).toFixed(1) + 'px'
// 下面是从命令行中获取 pdf的高度、宽度 和 pdf文件的路径
var width2 = system.args[2];
var height2 = system.args[3];
var pdfPath = system.args[4];
console.log(width2);
console.log(height2);
// 如果对pdf尺寸没有特殊要求也可以将宽度和高度写死
page.paperSize = { width: width2,height:height2};

page.open(address, function (status) {
    if (status !== 'success') {
        console.log('Unable to load the address!');
        phantom.exit(1);
    } else {
        window.setTimeout(function () {
            console.log("begin...");
            page.render(pdfPath);
            console.log(pdfPath);
            phantom.exit(); // 一定要调用这个方法
            console.log("end...");
        }, 1000);
    }
});

三、执行命令行语句验证pdf生成的效果

/test/phantomjs /test/html2pdf.js http://www.baidu.com 1000px 1000px /test/a.pdf

执行这条命令,检查生成pdf是否符合要求。如果不行则尝试调整参数或者脚本

四、java中调用命令

public static void html2Pdf(String phantomjs, String url, String html2pdfjs
		, Integer width, Integer height, String pdfPath) {
	InputStream is = null;
	try {
		System.out.println(url);
		File pdfFile = new File(pdfPath);
		File parentFile = pdfFile.getParentFile();
		if(!parentFile.exists()) {
			parentFile.mkdirs();
		}
		String os = System.getProperty("os.name").toLowerCase();
		String w = null, h = null;
		if(os.contains("linux")) {
			w = String.format("%.2f", width * 3.7794) + "px";
			h = String.format("%.2f", height * 3.7794) + "px";
		} else {
			w = width + "mm";
			h = height + "mm";
		}
		System.out.println(os + "===" + w + "=======" + h);
		//执行phantomjs 生成js
		Runtime rt = Runtime.getRuntime();
		String cmd = phantomjs + " " + html2pdfjs + " " + url + " " + w + " " + h + " " + pdfPath;
		System.out.println("cmd===" + cmd);
		Process p = rt.exec(cmd);
		is = p.getInputStream();
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		StringBuffer sbf = new StringBuffer();
		String tmp = "";
		while ((tmp = br.readLine()) != null) {
			sbf.append(tmp);
		}
		String resultstr = sbf.toString();
		System.out.println(resultstr);
		p.waitFor(); // 等待运行结束
	} catch (Exception e) {
		e.printStackTrace();
	} finally {
		if(is != null) {
			try {
				is.close();
			} catch (Exception e) {
			}
		}
	}
	return null;
}

width 和 height 两个参数在windos环境和在linux环境下传给phantomjs达到的效果竟然不一样,所以上面的程序专门做了不同的处理。

五、踩过的坑

1、linux下java调用命令及参数中如果带了 & 符号,会导致命令执行失败,同时又找不到原因。因为 & 符号在linux命令下有特殊的含义,因此 网页的url中如果带了&符号(比如url中的&是传递参数的)则pdf会生成不正确

2、如果尝试将带&的网页url 用引号包起来,在linux命令行下可以顺利执行,但是java的Runtime.exec()去执行命令还是不能正确生成pdf文件,好像是因为Runtime.exec()对参数中的引号进行特殊的处理。

因此,如果能自己控制网页url,则需要将网页url中的&替换掉,改成其他方式传参。如果是别人的网页url,在linux似乎没有好的办法解决。

六、参考资料

phantomjs 参考资料如下:
https://phantomjs.org/download.html
https://www.npmjs.com/package/phantom-html2pdf
https://phantomjs.org/api/webpage/property/paper-size.html

本文内容到此结束。

你可能感兴趣的:(pdf,phantomjs,前端,java)