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 <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

本文內容到此結束。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章