PhantomJS 把頁面轉成PDF 列印
阿新 • • 發佈:2019-01-09
由於專案需要把頁面打印出來,本專案是用ajax動態獲取表單資料的,很多資料通過瀏覽器列印無法實現完整資訊
於是想到爬蟲,通過PhantomJS 把頁面URL 抓取儲存未pdf 並把流資料返給前端附件下載
PhantomJS的安裝說明這裡不介紹了,pdf 儲存用了PhantomJS 自帶的rasterize.js
貼程式碼
html頁面 用easyui加了一個按鈕
<a href="javascript:void(0)" class="easyui-linkbutton" id="btnPdfExport" onclick="ACWS.html2Pdf()">PDF匯出</a>
js 把當前頁面的url 和 檔名傳給後端control 檔名用了頁面的title
/** * html 匯出 pdf * @returns */ ACWS.html2Pdf = function (){ var url = window.location.href; var fileName = $(document).attr("title"); $("body").mask(); window.location.href = acwsContext + "/rest/pdfdownload?url="+encodeURIComponent(url)+"&fileName="+encodeURIComponent(fileName); $("body").unmask(); }
control層 這裡有一個問題,Process 是子程序單獨處理的,但是通過process 去獲取流是空的,沒辦法這裡只有等附件生成結束後,在通過File 來獲取pdf的流資料返回給前端
/** * 版權所有:華信軟體 * 專案名稱:gx-pms * 建立者: diaoby * 建立日期: 2019年1月5日 * 檔案說明: PhantomControl PDF 匯出 */ package com.huaxin.gxgc.phantom.control; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.huaxin.acws.common.exception.AcwsGenerelException; import com.huaxin.acws.security.util.Security; import com.huaxin.acws.ucenter.model.User; import com.huaxin.gxgc.common.service.CommonService; import com.huaxin.gxgc.phantom.service.PhantomService; import io.swagger.annotations.Api; /** * @author diaoby * PhantomControl PDF 匯出 */ @Api(tags = {"PhantomControl"}) @RestController public class PhantomControl { /** * PhantomService */ @Resource private PhantomService phantomService; /** * 廣西工程公用服務類 */ @Resource private CommonService commonService; /** * 關閉命令和流 * @param process * @param inputStream * @throws IOException * @author diaoby */ private void close(Process process, InputStream inputStream) throws IOException { if (inputStream != null) { inputStream.close(); inputStream = null; } if (process != null) { process.destroy(); process = null; } } /** * 刪除PDF 臨時檔案 * @param pdfPath * @return * @author diaoby */ private void delPdfTempleFile(String pdfPath) { File pdfFile = new File(pdfPath); if(pdfFile.exists()){ pdfFile.delete(); } } /** * html 轉pdf * @param request * @return * @author diaoby * @throws UnsupportedEncodingException * @throws InterruptedException */ @RequestMapping("/pdfdownload") public ResponseEntity<byte[]> html2Pdf(HttpServletRequest request,@RequestParam("url") String url,@RequestParam("fileName")String fileName) throws UnsupportedEncodingException, InterruptedException{ byte[] body = null; HttpHeaders headers = new HttpHeaders(); fileName=new String(fileName.getBytes("UTF-8"),"iso-8859-1"); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDispositionFormData("attachment", fileName+".pdf"); ResponseEntity<byte[]> responseEntity = null; InputStream inputStream = null ; Process process = null; FileInputStream fis = null; ByteArrayOutputStream bos = null; String filePath = phantomService.pdfTempleFilePath(); User currentUser = Security.getCurrentUser(); String token = commonService.getToken2(currentUser.getLoginName()); //url 新增token 和 isPdf 引數,方便過濾頁面彈出框 url = url+"&Authorization="+token+"&isPdf=true"; try { process = phantomService.printUrlScreen2pdf(filePath,url); //等到 process 完成 產生pdf附件 process.waitFor(); //讀取產生的檔案到輸出流 File pdfFile = new File(filePath); if(pdfFile.exists()){ fis = new FileInputStream(pdfFile); bos = new ByteArrayOutputStream(); byte[] b = new byte[1024]; int n; while ((n = fis.read(b)) != -1) { bos.write(b, 0, n); } body = bos.toByteArray(); } responseEntity = new ResponseEntity<byte[]>(body,headers,HttpStatus.CREATED); } catch (IOException e) { throw new AcwsGenerelException("pdf匯出異常", e); } finally { try { fis.close(); bos.close(); close(process, inputStream); //刪除生產的pdf檔案 delPdfTempleFile(filePath); } catch (IOException e) { throw new AcwsGenerelException("pdf流關閉異常", e); } } return responseEntity; } }
因為系統有jwt 所以頁面url都加上了token
serivice 主要通過配置獲取了phantom安裝的路徑和js 還有pdf儲存的臨時目錄
/** * 版權所有:華信軟體 * 專案名稱:gx-pms * 建立者: diaoby * 建立日期: 2019年1月8日 * 檔案說明: Phantom service */ package com.huaxin.gxgc.phantom.service; import java.io.File; import java.io.IOException; import java.util.UUID; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; /** * @author diaoby * */ @Service public class PhantomService { /** * Phantom servie */ /** * 圖片儲存目錄 */ @Value("${phantom.pdf.tempPath}") private String tempPath ; /** * 空格 */ private String BLANK = " "; /** * phantomjs exe */ @Value("${phantom.exe}") private String binPath; /** * rasterize.js */ @Value("${phantom.rasterizejs}") private String jsPath; /** * 執行命令 * @param path * @param url * @return * @author diaoby */ public String cmd(String path, String url) { return binPath + BLANK + jsPath + BLANK + url + BLANK + path; } /** * 頁面轉pdf * @param url * @throws IOException * @author diaoby */ public Process printUrlScreen2pdf(String pdfPath,String url) throws IOException{ //Java中使用Runtime和Process類執行外部程式 String cmd = cmd(pdfPath,url); Process process = Runtime.getRuntime().exec(cmd); return process; } /** * 返回PDF 臨時生產目錄 * @param url * @author diaoby */ public String pdfTempleFilePath() { return tempPath+File.separator+UUID.randomUUID().toString()+".pdf"; } }
下載頁面
pdf下載