1. 程式人生 > >PhantomJS 把頁面轉成PDF 列印

PhantomJS 把頁面轉成PDF 列印

由於專案需要把頁面打印出來,本專案是用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下載