html轉為pdf的組件有很多,但是還沒有哪一款能達到這個效果,其只要原因是wkhtmltopdf使用webkit網頁渲染引擎開發的用來將 html轉成 pdf的工具,可以跟多種腳本語言進行集成來轉換文檔。但是就使用簡便性來說還是itext等組件占據優勢,如果你要轉換格式有比較高的要求,那么wkhtmltopdf絕對是不二之選!
下載路徑
官網地址 wkhtmltopdf.org/
github地址 github.com/wkhtmltopdf…
使用方法
java調用demo
public class HtmlToPdfInterceptor extends Thread { private InputStream is; public HtmlToPdfInterceptor(InputStream is){ this.is = is; } public void run(){ try{ InputStreamReader isr = new InputStreamReader(is, "utf-8"); BufferedReader br = new BufferedReader(isr); String line = null; while ((line = br.readLine()) != null) { System.out.println(line.toString()); //輸出內容 } }catch (IOException e){ e.printStackTrace(); } }}public class HtmlToPdf { //wkhtmltopdf在系統中的路徑 private static final String toPdfTool = "D:\wkhtmltopdf\bin\wkhtmltopdf.exe"; /** * html轉pdf * @param srcPath html路徑,可以是硬盤上的路徑,也可以是網絡路徑 * @param destPath pdf保存路徑 * @return 轉換成功返回true */ public static boolean convert(String srcPath, String destPath){ File file = new File(destPath); File parent = file.getParentFile(); //如果pdf保存路徑不存在,則創建路徑 if(!parent.exists()){ parent.mkdirs(); } StringBuilder cmd = new StringBuilder(); cmd.append(toPdfTool); cmd.append(" "); cmd.append(" --header-line");//頁眉下面的線 cmd.append(" --header-center 這里是頁眉這里是頁眉這里是頁眉這里是頁眉 ");//頁眉中間內容 //cmd.append(" --margin-top 30mm ");//設置頁面上邊距 (default 10mm) cmd.append(" --header-spacing 10 ");//(設置頁眉和內容的距離,默認0) cmd.append(srcPath); cmd.append(" "); cmd.append(destPath); boolean result = true; try{ Process proc = Runtime.getRuntime().exec(cmd.toString()); HtmlToPdfInterceptor error = new HtmlToPdfInterceptor(proc.getErrorStream()); HtmlToPdfInterceptor output = new HtmlToPdfInterceptor(proc.getInputStream()); error.start(); output.start(); proc.waitFor(); }catch(Exception e){ result = false; e.printStackTrace(); } return result; } public static void main(String[] args) { HtmlToPdf.convert("https://my.oschina.net/papio/blog/835645", "d:/wkhtmltopdf.pdf"); }}復制代碼
wkhtmltopdf 參數詳解
wkhtmltopdf [OPTIONS]... <input file> [More input files] <output file>常規選項 --allow <path> 允許加載從指定的文件夾中的文件或文件(可重復) --book* 設置一會打印一本書的時候,通常設置的選項 --collate 打印多份副本時整理 --cookie <name> <value> 設置一個額外的cookie(可重復) --cookie-jar <path> 讀取和寫入的Cookie,并在提供的cookie jar文件 --copies <number> 復印打印成pdf文件數(默認為1) --cover* <url> 使用HTML文件作為封面。它會帶頁眉和頁腳的TOC之前插入 --custom-header <name> <value> 設置一個附加的HTTP頭(可重復) --debug-javascript 顯示的javascript調試輸出 --default-header* 添加一個缺省的頭部,與頁面的左邊的名稱,頁面數到右邊,例如: --header-left '[webpage]' --header-right '[page]/[toPage]' --header-line --disable-external-links* 禁止生成鏈接到遠程網頁 --disable-internal-links* 禁止使用本地鏈接 --disable-javascript 禁止讓網頁執行JavaScript --disable-pdf-compression* 禁止在PDF對象使用無損壓縮 --disable-smart-shrinking* 禁止使用WebKit的智能戰略收縮,使像素/ DPI比沒有不變 --disallow-local-file-access 禁止允許轉換的本地文件讀取其他本地文件,除非explecitily允許用 --allow --dpi <dpi> 顯式更改DPI(這對基于X11的系統沒有任何影響) --enable-plugins 啟用已安裝的插件(如Flash --encoding <encoding> 設置默認的文字編碼 --extended-help 顯示更廣泛的幫助,詳細介紹了不常見的命令開關 --forms* 打開HTML表單字段轉換為PDF表單域 --grayscale PDF格式將在灰階產生 --help Display help --htmldoc 輸出程序HTML幫助 --ignore-load-errors 忽略claimes加載過程中已經遇到了一個錯誤頁面 --lowquality 產生低品質的PDF/ PS。有用縮小結果文檔的空間 --manpage 輸出程序手冊頁 --margin-bottom <unitreal> 設置頁面下邊距 (default 10mm) --margin-left <unitreal> 將左邊頁邊距 (default 10mm) --margin-right <unitreal> 設置頁面右邊距 (default 10mm) --margin-top <unitreal> 設置頁面上邊距 (default 10mm) --minimum-font-size <int> 最小字體大小 (default 5) --no-background 不打印背景 --orientation <orientation> 設置方向為橫向或縱向 --page-height <unitreal> 頁面高度 (default unit millimeter) --page-offset* <offset> 設置起始頁碼 (default 1) --page-size <size> 設置紙張大小: A4, Letter, etc. --page-width <unitreal> 頁面寬度 (default unit millimeter) --password <password> HTTP驗證密碼 --post <name> <value> Add an additional post field (repeatable) --post-file <name> <path> Post an aditional file (repeatable) --print-media-type* 使用的打印介質類型,而不是屏幕 --proxy <proxy> 使用代理 --quiet Be less verbose --read-args-from-stdin 讀取標準輸入的命令行參數 --readme 輸出程序自述 --redirect-delay <msec> 等待幾毫秒為JS-重定向(default 200) --replace* <name> <value> 替換名稱,值的頁眉和頁腳(可重復) --stop-slow-scripts 停止運行緩慢的JavaScripts --title <text> 生成的PDF文件的標題(第一個文檔的標題使用,如果沒有指定) --toc* 插入的內容的表中的文件的開頭 --use-xserver* 使用X服務器(一些插件和其他的東西沒有X11可能無法正常工作) --user-style-sheet <url> 指定用戶的樣式表,加載在每一頁中 --username <username> HTTP認證的用戶名 --version 輸出版本信息退出 --zoom <float> 使用這個縮放因子 (default 1) 頁眉和頁腳選項--header-center* <text> (設置在中心位置的頁眉內容) --header-font-name* <name> (default Arial) (設置頁眉的字體名稱)--header-font-size* <size> (設置頁眉的字體大小)--header-html* <url> (添加一個HTML頁眉,后面是網址)--header-left* <text> (左對齊的頁眉文本)--header-line* (顯示一條線在頁眉下)--header-right* <text> (右對齊頁眉文本)--header-spacing* <real> (設置頁眉和內容的距離,默認0)--footer-center* <text> (設置在中心位置的頁腳內容) --footer-font-name* <name> (設置頁腳的字體名稱) --footer-font-size* <size> (設置頁腳的字體大小default 11)--footer-html* <url> (添加一個HTML頁腳,后面是網址)--footer-left* <text> (左對齊的頁腳文本)--footer-line* 顯示一條線在頁腳內容上)--footer-right* <text> (右對齊頁腳文本)--footer-spacing* <real> (設置頁腳和內容的距離)./wkhtmltopdf --footer-right '[page]/[topage]' http://www.baidu.com baidu.pdf./wkhtmltopdf --header-center '報表' --header-line --margin-top 2cm --header-line http://192.168.212.139/oma/ oma.pdf表內容選項中 --toc-depth* <level> Set the depth of the toc (default 3) --toc-disable-back-links* Do not link from section header to toc --toc-disable-links* Do not link from toc to sections --toc-font-name* <name> Set the font used for the toc (default Arial) --toc-header-font-name* <name> The font of the toc header (if unset use --toc-font-name) --toc-header-font-size* <size> The font size of the toc header (default 15) --toc-header-text* <text> The header text of the toc (default Table Of Contents) --toc-l1-font-size* <size> Set the font size on level 1 of the toc (default 12) --toc-l1-indentation* <num> Set indentation on level 1 of the toc (default 0) --toc-l2-font-size* <size> Set the font size on level 2 of the toc (default 10) --toc-l2-indentation* <num> Set indentation on level 2 of the toc (default 20) --toc-l3-font-size* <size> Set the font size on level 3 of the toc (default 8) --toc-l3-indentation* <num> Set indentation on level 3 of the toc (default 40) --toc-l4-font-size* <size> Set the font size on level 4 of the toc (default 6) --toc-l4-indentation* <num> Set indentation on level 4 of the toc (default 60) --toc-l5-font-size* <size> Set the font size on level 5 of the toc (default 4) --toc-l5-indentation* <num> Set indentation on level 5 of the toc (default 80) --toc-l6-font-size* <size> Set the font size on level 6 of the toc (default 2) --toc-l6-indentation* <num> Set indentation on level 6 of the toc (default 100) --toc-l7-font-size* <size> Set the font size on level 7 of the toc (default 0) --toc-l7-indentation* <num> Set indentation on level 7 of the toc (default 120) --toc-no-dots* Do not use dots, in the toc輪廓選項 --dump-outline <file> 轉儲目錄到一個文件 --outline 顯示目錄(文章中h1,h2來定) --outline-depth <level> 設置目錄的深度(默認為4)頁腳和頁眉 * [page] 由當前正在打印的頁的數目代替 * [frompage] 由要打印的第一頁的數量取代 * [topage] 由最后一頁要打印的數量取代 * [webpage] 通過正在打印的頁面的URL替換 * [section] 由當前節的名稱替換 * [subsection] 由當前小節的名稱替換 * [date] 由當前日期系統的本地格式取代 * [time] 由當前時間,系統的本地格式取代
作者:曹元
鏈接:https://juejin.im/post/6856547881873047559
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
持原創,共同進步!請關注我,后續分享更精彩!
項目中經常有生成圖表報告的需求。實現的方式有很多,下面幾種方案,各有優缺點。
純java后端實現:后端JFreeChart等繪制庫畫好圖表,再通過itext庫導出為pdf。該方案能實現簡單的圖表功能,樣式、格式調整等可能會花大量時間。適合中小型報表開發項目。
前端繪制圖表,后端運行時命令調用wkhtmltopdf生成pdf:后端通過運行時命令調用node js,js使用wkhtmltopdf庫動態訪問報表url地址,HTML內容渲染完成后生成pdf文件。該方案,使用純前端js繪制圖表,能實現復雜需求。但wkhtmltopdf庫對不同瀏覽器的js存在兼容性問題,導出成pdf文件時存在各種坑,在單頁面技術支持還不太成熟。適合豐富報表的pdf導出,但兼容性問題維護成本太高。
前端繪制圖表,后端運行時命令調用puppeteer生成pdf:后端通過運行時命令調用node js,js使用puppeteer庫動態訪問報表url地址,HTML內容渲染完成后生成pdf文件。該方案和wkhtmltopdf方案類似,但兼容性更好。puppeteer是 Chrome 開發團隊在 2017 年發布的一個 Node.js 包,用來模擬 Chrome 瀏覽器的運行。可以在無界面的環境中運行Chrome或通過命令行、程序語言操作 Chrome。理論上Chrome中顯示的圖表,就能通過該庫生成一致的pdf文件內容,不用浪費很多時間在頁面樣式和兼容性問題上。
本文選擇puppeteer方案介紹如何生成一個pdf報表。細心的小伙伴可能注意到了,既然puppeteer是js庫,為什么不直接前端導出pdf,干嘛這么麻煩還通過后端繞一圈來實現?
這主要出于需求和用戶體驗的考慮,有些業務場景需要通過api接口動態生成pdf報表,不需要用戶訪問界面。如果生成的pdf的報表很大,直接在用戶端生成,可能占用大量客戶端資源,導致頁面崩潰或假死,從而影響使用體驗。
1.先安裝NodeJs,網上教程很多,本文不再贅述。
2.安裝puppeteer依賴,如果npm下載不成功就使用cnpm命令(cnpm需要先安裝)
npm install puppeteer --save
3.在安裝puppeteer依賴的目錄下創建page2pdf.js
const puppeteer = require('puppeteer');
const options = process.argv;
var siteUrl;
//執行 node page2pdf.js https://www.baidu.com
(async() => {
if(options.length>=3){
siteUrl=options[2];
//types=options[3];
//console.log(siteUrl);
}
const browser = await puppeteer.launch();
const page = await browser.newPage();
//console.log(options.length);
//console.log(options[0]);
//console.log(options[1]);
//console.log(options[2]);
//console.log(options[3]);
const userAgent = "Mozilla/5.0 (Linux; Android 8.1.0; MI 8 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36";
page.setUserAgent(userAgent);
await page.setViewport({ width: 1000, height: 1080 });
//await page.setViewport({ width: 480, height: 800,isMobile: true});
//通過css樣式可見,動態設置站點加載完成標識。
//page.waitForSelector('img').then(() => console.log('siteUrl with page load success: ' + siteUrl));
await page.goto(siteUrl, {timeout: 10*60000, waitUntil: 'networkidle2'});
/**await page.goto(siteUrl, {timeout: 10*60000, waitUntil: 'networkidle2'})
.catch(e => {
console.log(siteUrl+" is error:"+e);
browser.close()
});*/
const pdf = await page.pdf({
path: 'page.pdf', //便于測試驗證,實際使用時可屏蔽
format: 'A4'
});
await browser.close();
process.stdout.write(pdf);
})();
page2pdf.js文件引入puppeteer依賴庫,通過傳入siteUrl參數訪問HTML page頁面,page.pdf生成文件,再通過process.stdout.write(pdf)返回java后臺。
4.創建java PuppeteerHtmlToPdf.java文件
/**
* 用谷歌提供的node實現的Puppeteer,實現網頁生成pdf文件
*/
public class PuppeteerHtmlToPdf {
/**
* html轉pdf,直接通過流輸出到瀏覽器
* @param response 瀏覽器響應
* @param fileName 文件名稱
* @param puppeteerjs 要采用哪個js文件執行
* @param webSiteUrl 要生成pdf的網頁
*/
public static void parseHtml2Pdf(HttpServletResponse response, String fileName, String puppeteerjs, String webSiteUrl) {
try {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("node "+puppeteerjs+" "+webSiteUrl);
InputStream is = p.getInputStream();
BufferedInputStream bf=new BufferedInputStream(is);
byte[] data = IOUtils.toByteArray(bf);
fileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
response.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream;charset=UTF-8");
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
outputStream.write(data);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.報表生成
page2pdf.js頁面目錄打開命令行,執行指令。
運行指令,生成pdf
node page2pdf.js https://www.baidu.com
查看對應目錄,已動態生成了一個page.pdf文件
打開pdf文件,對應HTML內容已生成。
本文介紹了報表導出pdf的3種方式,通過優缺點分析,詳細闡述了puppeteer的實現方式。并通過百度頁面的pdf導出做了演示。
希望本文對有類似報表pdf導出需求的小伙伴有所參考和幫助。若存在不足或更好方案,請留言討論。
在前面:java作為一門世界級編程語言金字塔頂尖的語言。需要大量的練習、練習、練習來鞏固自己所獲得的知識。冰凍三尺非一日之寒,希望大家在學習java的日子里一定一定要堅持不懈,嚴格要求。多練,多問,多百度。祝大家早日成為一名優秀的軟件工程師!
文章摘要:此篇文章會帶領大家創建一個html最簡單的頁面,以及在頁面中增加一些簡單的內容。
我先給大家放2張我以前教學的時候,開課前給學生畫的圖:
這2張圖應該已經比較清晰明了的告訴你,學習java前端需要具備的一些主觀和客觀方面的東西,我就不多做解釋了,以后我的文章中,會以代碼圖片及展現效果居多,盡量減少文字的占比。讓大家對所學的知識有一個更直觀的感受。
言歸正傳,想要編寫html代碼,首先需要一個后綴為.html的文件,這個文件怎么創建呢?最簡單的方式,建一個txt,然后把后綴改為.html,用編輯器打開,就可以編寫代碼了。
當然,txt界面太丑,筆者這里選用sublime,該編輯器也可以直接加載一個html模板,選擇菜單→新建文件(模板)→html,當然,前提要先設置好這個模板,具體設置方法這里就不做詳細介紹了,百度上一大堆。新建完成后,產生一個代碼如下的頁面:
然后在<body></body>標簽體之間打入一行代碼
用瀏覽器打開該文件,顯示如下圖,說明這個html文件已經創建成功了,能夠正常的編寫代碼。
零基礎的同學一定對剛才的代碼比較疑惑,雖然照著寫能實現功能,但是這些代碼各自又都是什么意義呢? 我用注釋的方式上圖來告訴大家:
首先,html 的標簽分為自閉和標簽和閉合標簽
自閉和標簽:就是沒有結束標簽,比如上圖的<meta>標簽,該標簽是沒有結束標簽相呼應的。
閉合標簽:有開始和結束標簽,比如上圖的<html><body><h1>標簽,他們都有一個</html></body></h1>相呼應
在上圖中,我用過了比較多的 < !-- -- >標簽,這是html里的注釋標簽,在編寫代碼的過程中,勤加注釋是一個非常非常好的習慣,不僅方便了他人也方便了以后自己代碼的維護。所以說,不加注釋的代碼都是在耍流氓。
我們80%的頁面標簽代碼都會寫在<body></body>標簽里面,什么是標簽,至少包含< > 和標簽元素,比如<div><a><p><input>等,標簽還有標簽屬性和屬性值,標簽屬性和屬性值在第一個標簽內容中,如果是多個標簽則以空格符號分割 ,如圖:
Div 是整個html中最常用的一個標簽元素,<div></div>類似于一個盒子,里面可以承載各種各樣的元素標簽,大家看到的所有的網站都是靠著div一個個的盒子規劃開來,最后拼接在一起的,形成了一個完整的頁面。
那么如何去建立一個div呢?首先,我們在html的<body></body>標簽中加入一個<div></div>標簽 ,但是單純的加入標簽并不會在頁面中產生肉眼可見的東西,因為我們還要定義這個div的寬,高,背景色,邊框等等,詳見如下代碼:
這樣的一行代碼,最后展現出來的效果是:
我們來一點點的剖析這一行代碼:
Style:style 是元素標簽里的一個標簽屬性,他的作用是可以定義該標簽的樣式。里面的樣式格式是xxx:xxx; 每一組樣式都是這樣的定義,冒號用來隔開樣式屬性和樣式屬性值,最后以分號結尾.
width:定義該元素的寬
height:定義該元素的高
background:定義該元素的背景顏色(也可使用red,yellow等顏色定義)
border:定義該元素的邊框
4px 代表邊框粗細,
solid 代表邊框樣式, 邊框樣式又分為solid(實框)、dotted(虛框)
red代表邊框顏色,邊框顏色也可用#ccc,#112233這種形式表現
Div里可以放入文字、圖片、標簽元素等各式各樣的東西。下面我演示一下如何放入照片:
首先,放入照片要使用到<img>標簽,這是一個自閉和標簽,所有沒有結束標簽。
Src代表圖片的路徑,width,height 代表圖片的寬度和高度 ,alt是圖片的描述
這個路徑可以是相對路徑,也可以是絕對路徑。
相對路徑:就是相對于這個網頁的路徑,比如圖片和網頁在同一個文件夾下,那么src處就直接填圖片的文件名字就可以,若建了一個文件夾images,圖片放在該文件夾中,同時這個文件夾和網頁在同一個位置,那么src所填的就是images/圖片名字.jpg
絕對路徑:即從頭開始寫路徑,如src = “C:/xxx/xxx/xxx/xxx.jpg”
假設我現在的圖片位置和網頁位置同處一處
最后的效果:
我這里改大了DIV的寬度和高度,若圖片所設的寬高大于DIV的寬度高度,那么將會發生溢出的情況,同學們可以自己去試一下,這種溢出的情況也有對應的標簽可以做調整,這個我們后面再講。
這邊特別提醒一點,如果div沒有設定寬度width,則默認為等同瀏覽器寬度的寬度,若div沒有設定高度,則該div根據div中內容進行高度的伸縮,div中的內容有多高,div就有多高,如圖,我把width和height全部去掉:
上圖width和height全部去掉,所以,width默認跟瀏覽器寬度等寬,高度為圖片的高度。
文字的話就比較簡單了,代碼貼上:
最后結果:
第二句文字才是div創建出來的文字,我解釋一下style里面的樣式:
Font-size:文字大小,px為單位(像素)
Font-family:文字樣式,分為很多,這個可以去word文檔里找找
Font-weight:文字加粗,bold是一種默認加粗的大小。
End.
來源:公眾號“java編程”
運行人員:中國統計網小編(微信號:itongjilove)
微博ID:中國統計網
中國統計網,是國內最早的大數據學習網站,公眾號:中國統計網
http://www.itongji.cn
*請認真填寫需求信息,我們會在24小時內與您取得聯系。