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 <html URL> <pdf_width> <pdf_height> <pdfPath>');
//這行代碼很重要。凡是結束必須調用。否則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
本文內容到此結束。