關於WkHtmltopdf插件將網頁導出成PDF的使用(一)

一、Wkhtmltopdf介紹

首先,先放一下Wkhtmltopdf工具的官網和下載連接:

下面正式開始介紹wkhtmltopdf:

1. wkhtmltopdf 簡介

工具全名叫 “wkhtmltopdf” ; 是一個使用 Qt WebKit 引擎做渲染的,能夠把html 文檔轉換成 pdf 文檔 或 圖片(image) 的命令行工具。支持多個平臺,可在win,linux,os x等系統下運行。

2. wkhtmltopdf 優點

  • 生成PDF時會自動根據你在HTML頁面中H系(<h1> <h2> 等等)標籤生成樹形目錄結構。
  • 小巧方便,轉換速度快。
  • 跨平臺。PS:目前只在Linux和Windows下用過

3. wkhtmltopdf 缺點

在實際使用中發現 wkhtmltopdf 工具並不是非常完美的:

  • 在導出pdf時,會洗掉 部分css樣式。
  • 在導出圖表時,非矢量圖失真的厲害。

4. wkhtmltopdf 安裝與配置

  1. 點上面的下載地址,點擊下載並安裝 wkhtmltopdf。
  2. PATH中添加配置你的wkhtmltopdf安裝目錄\bin
  3. 檢查你的 wkhtmltopdf是否配置成功,打開終端,輸入 wkhtmltopdf -V如果出現 wkhtmltopdf 工具的版本信息則說明你已經可以使用該工具了。

5. wkhtmltopdf 使用

  1. 命令行操作
  2. 通過代碼操作

第一種操作方式網上有很多教程,在此不再贅述。我在這裏講一講在代碼中使用wkhtmltopdf。

二、代碼中操作 wkhtmltopdf

1. 介紹一下wkhtmltopdf 中的幾種對象:

  • 文檔對象
    “文檔對象”是指PDF文檔中的文檔對象,共有三種類型的“文檔對象”,他們分別是“頁面對象”,“封面對象”和“目錄對象”。
  • 頁面對象
    “頁面對象”是指以頁面的形式在PDF文檔中呈現的對象,這個是相對於“封面對象”和“目錄對象”來講的。此類對象會成爲PDF文檔中內容。
  • 封面對象
    “封面對象”是指以封面的形式在PDF文檔中呈現的對象。這類對象會成爲PDF文檔中的封面。
  • 目錄對象
    “目錄對象”是以目錄的形式在PDF文檔中呈現的對象,又叫“TOC對象”。這類對象會成爲PDF文檔中的目錄。

這一部分我大體羅列這四部分,至於其他的術語和具體的命令請移駕到JSON_NULL的簡書查看。

2. wkhtmltopdf 的應用場景

開發過B/S端金融項目的小夥伴們應該對報表不陌生,那麼wkhtmltopdf的一個應用場景就是導出報表。對我來說也是最主要的應用場景。

3. wkhtmltopdf 的實際操作(Java)

1. 新建一個Java類htmltopdf

    	public class CrHtmlToPdf {
			/**
	    	 * 將HTML文件內容輸出爲PDF文件
			 * 若不使用自定義頁眉頁腳請使用兩參的htmlToPdf();
	    	 * @param htmlFileName HTML文件名
	    	 * @param headerHtmlName  自定義頁眉/頁腳文件路徑
	    	 * @param coverHtml  封面
	    	 * @param pdfFileName  PDF文件名
	    	 */
    		public boolean htmlToPdf(String htmlFileName,String headerHtmlName,String coverHtml,String pdfFileName) {
        		this.pdfName = pdfFileName;
        		boolean result = true;
        		try {
            		//調用和執行wkhtmltopdf命令
            		StringBuilder cmd = new StringBuilder();
            		//如果wkhtmltopdf沒有加入環境變量,可以寫成wkhtmltopdf所在的絕對目錄
            		cmd.append("wkhtmltopdf");
            		/*cmd.append(" ");
            		//編碼
            		cmd.append("--encoding utf8");
            		cmd.append(" ");
            		//指定一個要分辨率(這在 X11 系統中並沒有什麼卵用)
            		cmd.append("-d 800");
            		cmd.append(" ");
            		//設置頁面寬度
		            cmd.append("--page-width 12.7cm");
		            cmd.append(" ");
		            //設置紙張大小
		            cmd.append("--page-size A4");
		            cmd.append(" ");
		            //靜態模式,不在標準輸出中打印任何信息
		            cmd.append("--quiet");
		            cmd.append(" ");
		            //不使用智能收縮策略,防止變形
		            *//*cmd.append("--disable-smart-shrinking");
		            cmd.append(" ");*//*
		            //不執行Javascript
		            cmd.append("--disable-javascript");
		            cmd.append(" ");*/
		
		            cmd.append(" ");
		            //編碼
		            cmd.append("--encoding utf8");
		            cmd.append(" ");
		            //指定一個要分辨率(這在 X11 系統中並沒有什麼卵用)
		            cmd.append("-d 2000");
		            cmd.append(" ");
		            //靜態模式,不在標準輸出中打印任何信息
		            cmd.append("--quiet");
		            cmd.append(" ");
		            //不使用智能收縮策略,防止變形
		            /*cmd.append("--disable-smart-shrinking");
		            cmd.append(" ");*/
		            //執行Javascript
		            cmd.append("--enable-javascript");
		            cmd.append(" ");
		            //生成頁眉
		            cmd.append("--margin-top 25");
		            cmd.append(" ");
		            cmd.append(" --header-html file:///"+headerHtmlName+" ");
		            cmd.append("--header-spacing 10 ");
		            cmd.append(" ");
		            //生成頁腳
		            cmd.append("  --footer-left \"敬請閱讀文末的法律說明\"  --footer-center \"[page]/[toPage]\" --footer-font-size 8 --footer-line");
		            cmd.append(" ");
		            cmd.append("--outline cover file:///"+coverHtml);
		            cmd.append(" ");
		            cmd.append(" toc --toc-header-text \"目錄\"");
		            cmd.append(" ");
		
		
		            //html文件目錄
		            cmd.append(htmlWorkRoot + htmlFileName);
		            cmd.append(" ");
		            //pdf文件目錄
		            cmd.append(pdfWorkRoot + pdfFileName);
		            cmd.append(" ");
		
		            //執行命令Thread
		            //System.err.println("------Start wkhtmltopdf");
		            Process process = Runtime.getRuntime().exec(cmd.toString());
		            //System.err.println(cmd.toString());
		            //new Thread(new HtmlToPdfThread(process.getInputStream())).start();
		            process.waitFor();
		        } catch (Exception e) {
		            result = false;
		            throw new RuntimeException(e);
		        }
		        return result;
			} 
	}

2. 要導出頁面的獲取

這裏只簡單講一下思路,具體代碼就不拋出來了。
1. 將要導出的HTML頁面轉換成html字符串
2. 將html字符串寫入到本地文件夾中,生成新的臨時html文件。

3. 頁眉的自定義

這裏要實現的頁眉樣式爲左上角是logo(關於logo圖片的處理稍後再講解),右上角文字隨報告文件名變化而變化。

這裏我是這麼解決的
1. 創建css字符串,html字符串。
2. 拼接需要設定的css樣式。
3. 拼接完整的html頁。
4. 將html字符串寫入文件中。

創建html字符串,拼接css和html

       /**
         * 生成頁眉html的字符串,準備生成html文件
         * @param logoPath Logo存放的路徑
         * @param templateName 當前查詢的報告名
         * @return 返回生成的html字符串
         */
    private String buildHeaderHtmlStr(String logoPath,String templateName){
        StringBuffer buffer = new StringBuffer();
        //創建css字符串
        StringBuffer cssBuffer = new StringBuffer();
        //拼接css字符串
        //創建css標籤
        cssBuffer.append("<style type=\"text/css\">\n");
        cssBuffer.append(".box{\n" +
                "            width: 1100px;\n" +
                "            height: 55px;\n" +
                "            position: relative;\n" +
                "        }\n");
        cssBuffer.append(".logo{\n" +
                "            width: 180px;\n" +
                "            height: 55px;\n" +
                "            left: 20px;\n" +
                "            position: absolute;\n" +
                "        }\n");
        cssBuffer.append(".text{\n" +
                "            width: 836px;\n" +
                "            height: 50px;\n" +
                "            position: absolute;\n" +
                "            left: 235px;\n" +
                "            top: 10px;\n" +
                "            background-color: #fff;\n" +
                "        }\n");
        cssBuffer.append(".text_title{\n" +
                "            width: 826px;\n" +
                "            height: 50px;\n" +
                "            border-bottom: 2px solid #c00000;\n" +
                "            text-align: right;\n" +
                "            left: 235px;\n" +
                "            line-height: 73px;\n" +
                "            padding: 0px;\n" +
                "            margin: 0px;\n" +
                "            color: #808080;\n" +
                "            font-size: 14px;\n" +
                "        }\n");
        cssBuffer.append("</style>\n");
        //聲明文檔標籤
        buffer.append("<!DOCTYPE html>\n");
        //組裝<head></head>內容
        buffer.append("<html lang=\"en\">\n" +
                "<head>\n<meta charset=\"UTF-8\">\n" +
                "    <title>自定義頁眉</title>\n"+cssBuffer.toString()+"\n</head>");
        buffer.append("<body>\n");
        //組裝logo div
        buffer.append("<div class=\"box\">\n" +
                "    <div class=\"logo\">\n" +
                "        <img src=\""+logoPath+"\">\n" +
                "    </div>\n");
        //組裝頁眉右側文字
        buffer.append("<div class=\"text\">\n" +
                "        <p class=\"text_title\">"+templateName+"</p>\n" +
                "    </div>\n");
        buffer.append("</div>\n</body>\n</html>");
//        System.err.println("Html字符串:"+buffer.toString());
        return buffer.toString();
    }

將html字符串寫入到文件中

	/**
     * 生成頁眉html文件,並返回其所在的路徑
     * @param templateName 當前查詢的報告名
     * @return 返回生成的headerHtml文件路徑
     */
    public String getHeaderPath(String templateName){
        String htmlFileName = "headerHtml" + System.currentTimeMillis()+".html";
        String htmlFileString = buildHeaderHtmlStr(getThematicImageString(LOGO_PATH), templateName);
        String savePath = HTML_PATH+"/"+htmlFileName;
        writingFile(savePath,htmlFileString);

//        System.err.println(savePath);
        return savePath;
    }

4. 封面的自定義

一般來說封面應該由兩部分組成,一個是封面背景(圖片),還有一個就是封面上的說明文字 所以封面處理與頁眉處理類似,那麼這個地方就直接放代碼不在贅述了。

先處理html字符串

	/**
     * 封面頁面HTML拼接
     * @param imagePath 背景圖片路徑
     * @return
     */
    public String bulidCoverHtmlStr(String imagePath){
        StringBuffer css = new StringBuffer();
        css.append("<style type=\"text/css\">\n");
        css.append(".toggleDiv{ position: relative;height:100%;margin-top: 2px;width:1000px;margin:0 auto;page-break-inside:avoid;}");
        css.append(".static_tables>p {font-size:20px !important;}");
        css.append(".mod_title{text-align: left;padding:30px 0 0 0}");
        css.append(".mod_title>hr{ height:2px;border:none;border-top: 2px solid #fff;margin: 0px}");
        css.append(".mod_title>h1{display: inline-block;font-size: 26px;margin-bottom: 0px;margin-top: 10px;position: relative;top: -14px;padding: 0 20px;background: #FFF;  font-weight: 700;color: #000;}");
        css.append(".mod_title>h2{display: inline-block;font-size: 26px;margin-bottom: 0px;margin-top: 10px;position: relative;top: -14px;padding: 0 20px;background: #FFF;  font-weight: 700;color: #000;}");
        css.append(".null_data{text-align: center}");
        css.append(".half{padding:0px 40px 0px 30px}");
        css.append(".half>div{width:50%;display: inline-block;height:300px}");
        css.append(".half>.static_tables{position: absolute;padding:20px 0px}");
        css.append(".half>.static_tables>table{position: absolute;top: 12%;margin: auto;left: 0;right: 0;width: 94%;padding: 0;table-layout:fixed}");
        css.append(".echartDiv{padding: 10px 0;color: #333;/*font-family: FangSong;*/font-size:50px !important;text-align:center;width:100%;height:300px;line-height: 15;}");
        css.append(".toggleDiv>.description{ line-height: 25px;font-family:STKaiti;font-size: 18px !important;margin-left: 40px;display: block;line-height:30px;padding-right:2%;}");

        css.append(".static_tables {padding: 20px 40px 20px 30px;}");
        css.append(".static_tables>p {font-size:20px !important;}");
        css.append(".static_tables>table{border-spacing:0px;width:100%}");
        css.append(".static_tables>table>thead>tr{background-color: #464d6c}");
        css.append(".static_tables>table>thead>tr>th{font-weight:bold; font-size: 16px !important; color: #fff !important;}");

        css.append(".static_tables>table th,.static_tables>table td{border-bottom:1px solid #d4d4d4;border-left:1px solid #d4d4d4;text-align:center;/*font-family: FangSong;*/font-size: 16px !important;height:40px;color: #333;word-wrap:break-word;word-break:break-all;line-height:25px; padding: 5px 10px;}");
        css.append(".static_tables>table th:last-child,.static_tables>table td:last-child{border-right:1px solid #d4d4d4;}");
        css.append(".static_tables>table>tbody>tr:nth-child(2n){ background-color: #fff}");
        css.append(".static_tables>table tr:first-child td{border-top: 1px solid #d4d4d4}");
        css.append(".titleDiv { position: relative;top:14px;display: block;width: 100%;text-align: center}");
        css.append(".toggleDiv>.title{/*font-family:FangSong;*/font-size:16px;color:#000}");

        css.append(".bz_box{width: 100%; height: 100%;border: 1px solid #e0e0e1;margin: 0 auto;}");
        css.append(".bz_box_title {border-bottom: 1px solid #e0e0e1;background-color: #ebecf3;padding-left: 20px;height: 35px;line-height: 35px;font-weight: bold;}");
        css.append(".bz_box_con {height: 100%;overflow: auto;padding-left:20px;padding-right: 10px;;line-height: 30px;}");
        css.append(".bz_box_con p{ padding: 0px;margin: 0px;}");
        css.append(".bz_box_con p span{font-weight: bold;}");
        css.append("</style>\n");
        StringBuilder htmlStr = new StringBuilder();
        htmlStr.append("<!DOCTYPE html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"></meta>");
        htmlStr.append("<style type=\"text/css\">html,body{height:100%;} span{display: block;font-size: 36px;padding: 12px;} .test{left:3%;top: 73%;bottom: 25%;right: 3%;position: relative;width: 1330px;} .cover2{left:3%; right: 5%;top: 78%;bottom: 22%;width: 1330px;position: relative;background-color: white; font-size:26px;} span>i{font-style: normal;padding: 0 5px;}");
        htmlStr.append("</style>");
        htmlStr.append(css.toString());
        htmlStr.append("</head><body><div style=\"width:1400px;height:1850px;\"><div style=\"background-size:100% 100%;width:100%;height:100%;background:url("+imagePath+") no-repeat\">");
        htmlStr.append("<div class=\"test\" style=\"background-color:red\"></div>");
        htmlStr.append("</body></html>");
        return htmlStr.toString();
    }

在生成html文件

public String getCoverPath() {
        String htmlFileName = "coverHtml" + System.currentTimeMillis() + ".html";
        String htmlFileString = bulidCoverHtmlStr(getThematicImageString(COVER_BGM_PATH));
        String savePath = HTML_PATH + "/" + htmlFileName;
        writingFile(savePath,htmlFileString);
//        System.err.println(savePath);
        return savePath;
    }

細心的小夥伴們看到這裏會發現,在這兩個拼接的方法裏都用到了一個getThematicImageString(String arg)的方法,但是這個方法我去沒有給出代碼,難道說這是一個Java本身就定義好的方法嗎?當然不是,這個方法就是在圖片處理時要用的方法。

5. 獲取資源圖片

在 Java web項目中,在編寫項目的時候就會把所有的靜態資源,例如image,.css文件,.js文件,.html文件等等的放在webapp文件夾中。那麼這樣的資源在編譯後會被放到/WEB-INF/classes/文件夾下,所以在這裏我們要對圖片進行處理,獲取圖片。

    /**
     * 獲取圖片
     * @param path 圖片路徑
     * @return
     */
    private String getThematicImageString(String path){
        InputStream inputStream = null;
        byte[] data = null;
        String classPath = this.getClass().getClassLoader().getResource("/").getPath();
        String fileNameT = path;
        String rootPathT;

        if("\\".equals(File.separator)){
            //Windows
            rootPathT = classPath.substring(1,classPath.indexOf("/WEB-INF/classes"));
            fileNameT = (rootPathT+File.separator+fileNameT).replace("/", "\\");
        }else if("/".equals(File.separator)){
            //linux
            rootPathT = classPath.substring(0,classPath.indexOf("/WEB-INF/classes"));
            fileNameT = (rootPathT+File.separator+fileNameT).replace("\\", "/");
        }

        try {
            inputStream = new FileInputStream(fileNameT);
            data = new byte[inputStream.available()];
            inputStream.read(data);
        } catch (IOException e) {
            UnitedLogger.error("加載圖片"+e.getMessage(), e);
        }finally {
            if(inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException io){
                    UnitedLogger.error("關閉流失敗"+io.getMessage(), io);
                }
            }
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return "data:image/png;base64,"+encoder.encode(data).replaceAll("\r\n","");
    }

這裏使用了base64 對圖片進行編碼。[小Q一下,這裏用base64進行編碼處理的原因]

6.寫文件

當然在整個過程中還缺少一個方法,就是寫文件的方法,由於該方法在同一個類中多次被用到,所以就把他抽出來,作爲一個公共方法。

寫文件

    private void writingFile(String path,String fileText){
        FileOutputStream fos;
        BufferedWriter bw;
        try {
            fos = new FileOutputStream(path);
            bw = new BufferedWriter(new OutputStreamWriter(fos,"UTF-8"));
            bw.write(fileText);
            bw.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

7. 代碼整合

最後,我們將這些方法放到同一個類中,形成一個DiyUtil類:

/**
 *
 * 〈自定義工具類〉
 *
 * @author fritain
 * @create 2019/4/26
 * @version v0.0.1
 */
public class DiyUtil {
    /**
     * LOGO_PATH logo地址
     */
    private static final String LOGO_PATH = PropertyReader.getValue("conf.properties", "con.report.logoUrl");
    /**
     * COVER_BGM_PATH 封面圖片存放位置
     */
    private static final String COVER_BGM_PATH = PropertyReader.getValue("conf.properties", "con.report.coverBgpUrl");
    /**
     * HTML_PATH 用於臨時存放生成的HTML
     */
    private static final String HTML_PATH = PropertyReader.getValue("conf.properties", "con.report.htmlUrl");
    
    /**
     * 生成頁眉html文件,並返回其所在的路徑
     * @param templateName 當前查詢的報告名
     * @return 返回生成的headerHtml文件路徑
     */
    public String getHeaderPath(String templateName){
        String htmlFileName = "headerHtml" + System.currentTimeMillis()+".html";
        String htmlFileString = buildHeaderHtmlStr(getThematicImageString(LOGO_PATH), templateName);
        String savePath = HTML_PATH+"/"+htmlFileName;
        writingFile(savePath,htmlFileString);

//        System.err.println(savePath);
        return savePath;
    }
    public String getCoverPath() {
        String htmlFileName = "coverHtml" + System.currentTimeMillis() + ".html";
        String htmlFileString = bulidCoverHtmlStr(getThematicImageString(COVER_BGM_PATH));
        String savePath = HTML_PATH + "/" + htmlFileName;
        writingFile(savePath,htmlFileString);
//        System.err.println(savePath);
        return savePath;
    }

        /**
         * 生成頁眉html的字符串,準備生成html文件
         * @param logoPath Logo存放的路徑
         * @param templateName 當前查詢的報告名
         * @return 返回生成的html字符串
         */
    private String buildHeaderHtmlStr(String logoPath,String templateName){
        StringBuffer buffer = new StringBuffer();
        //創建css字符串
        StringBuffer cssBuffer = new StringBuffer();
        //拼接css字符串
        //創建css標籤
        cssBuffer.append("<style type=\"text/css\">\n");
        cssBuffer.append(".box{\n" +
                "            width: 1100px;\n" +
                "            height: 55px;\n" +
                "            position: relative;\n" +
                "        }\n");
        cssBuffer.append(".logo{\n" +
                "            width: 180px;\n" +
                "            height: 55px;\n" +
                "            left: 20px;\n" +
                "            position: absolute;\n" +
                "        }\n");
        cssBuffer.append(".text{\n" +
                "            width: 836px;\n" +
                "            height: 50px;\n" +
                "            position: absolute;\n" +
                "            left: 235px;\n" +
                "            top: 10px;\n" +
                "            background-color: #fff;\n" +
                "        }\n");
        cssBuffer.append(".text_title{\n" +
                "            width: 826px;\n" +
                "            height: 50px;\n" +
                "            border-bottom: 2px solid #c00000;\n" +
                "            text-align: right;\n" +
                "            left: 235px;\n" +
                "            line-height: 73px;\n" +
                "            padding: 0px;\n" +
                "            margin: 0px;\n" +
                "            color: #808080;\n" +
                "            font-size: 14px;\n" +
                "        }\n");
        cssBuffer.append("</style>\n");
        //聲明文檔標籤
        buffer.append("<!DOCTYPE html>\n");
        //組裝<head></head>內容
        buffer.append("<html lang=\"en\">\n" +
                "<head>\n<meta charset=\"UTF-8\">\n" +
                "    <title>自定義頁眉</title>\n"+cssBuffer.toString()+"\n</head>");
        buffer.append("<body>\n");
        //組裝logo div
        buffer.append("<div class=\"box\">\n" +
                "    <div class=\"logo\">\n" +
                "        <img src=\""+logoPath+"\">\n" +
                "    </div>\n");
        //組裝頁眉右側文字
        buffer.append("<div class=\"text\">\n" +
                "        <p class=\"text_title\">"+templateName+"</p>\n" +
                "    </div>\n");
        buffer.append("</div>\n</body>\n</html>");
//        System.err.println("Html字符串:"+buffer.toString());
        return buffer.toString();
    }

    /**
     * 封面頁面HTML拼接
     * @param imagePath 背景圖片路徑
     * @return
     */
    public String bulidCoverHtmlStr(String imagePath){
        StringBuffer css = new StringBuffer();
        css.append("<style type=\"text/css\">\n");
        css.append(".toggleDiv{ position: relative;height:100%;margin-top: 2px;width:1000px;margin:0 auto;page-break-inside:avoid;}");
        css.append(".static_tables>p {font-size:20px !important;}");
        css.append(".mod_title{text-align: left;padding:30px 0 0 0}");
        css.append(".mod_title>hr{ height:2px;border:none;border-top: 2px solid #fff;margin: 0px}");
        css.append(".mod_title>h1{display: inline-block;font-size: 26px;margin-bottom: 0px;margin-top: 10px;position: relative;top: -14px;padding: 0 20px;background: #FFF;  font-weight: 700;color: #000;}");
        css.append(".mod_title>h2{display: inline-block;font-size: 26px;margin-bottom: 0px;margin-top: 10px;position: relative;top: -14px;padding: 0 20px;background: #FFF;  font-weight: 700;color: #000;}");
        css.append(".null_data{text-align: center}");
        css.append(".half{padding:0px 40px 0px 30px}");
        css.append(".half>div{width:50%;display: inline-block;height:300px}");
        css.append(".half>.static_tables{position: absolute;padding:20px 0px}");
        css.append(".half>.static_tables>table{position: absolute;top: 12%;margin: auto;left: 0;right: 0;width: 94%;padding: 0;table-layout:fixed}");
        css.append(".echartDiv{padding: 10px 0;color: #333;/*font-family: FangSong;*/font-size:50px !important;text-align:center;width:100%;height:300px;line-height: 15;}");
        css.append(".toggleDiv>.description{ line-height: 25px;font-family:STKaiti;font-size: 18px !important;margin-left: 40px;display: block;line-height:30px;padding-right:2%;}");

        css.append(".static_tables {padding: 20px 40px 20px 30px;}");
        css.append(".static_tables>p {font-size:20px !important;}");
        css.append(".static_tables>table{border-spacing:0px;width:100%}");
        css.append(".static_tables>table>thead>tr{background-color: #464d6c}");
        css.append(".static_tables>table>thead>tr>th{font-weight:bold; font-size: 16px !important; color: #fff !important;}");

        css.append(".static_tables>table th,.static_tables>table td{border-bottom:1px solid #d4d4d4;border-left:1px solid #d4d4d4;text-align:center;/*font-family: FangSong;*/font-size: 16px !important;height:40px;color: #333;word-wrap:break-word;word-break:break-all;line-height:25px; padding: 5px 10px;}");
        css.append(".static_tables>table th:last-child,.static_tables>table td:last-child{border-right:1px solid #d4d4d4;}");
        css.append(".static_tables>table>tbody>tr:nth-child(2n){ background-color: #fff}");
        css.append(".static_tables>table tr:first-child td{border-top: 1px solid #d4d4d4}");
        css.append(".titleDiv { position: relative;top:14px;display: block;width: 100%;text-align: center}");
        css.append(".toggleDiv>.title{/*font-family:FangSong;*/font-size:16px;color:#000}");

        css.append(".bz_box{width: 100%; height: 100%;border: 1px solid #e0e0e1;margin: 0 auto;}");
        css.append(".bz_box_title {border-bottom: 1px solid #e0e0e1;background-color: #ebecf3;padding-left: 20px;height: 35px;line-height: 35px;font-weight: bold;}");
        css.append(".bz_box_con {height: 100%;overflow: auto;padding-left:20px;padding-right: 10px;;line-height: 30px;}");
        css.append(".bz_box_con p{ padding: 0px;margin: 0px;}");
        css.append(".bz_box_con p span{font-weight: bold;}");
        css.append("</style>\n");
        StringBuilder htmlStr = new StringBuilder();
        htmlStr.append("<!DOCTYPE html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\"></meta>");
        htmlStr.append("<style type=\"text/css\">html,body{height:100%;} span{display: block;font-size: 36px;padding: 12px;} .test{left:3%;top: 73%;bottom: 25%;right: 3%;position: relative;width: 1330px;} .cover2{left:3%; right: 5%;top: 78%;bottom: 22%;width: 1330px;position: relative;background-color: white; font-size:26px;} span>i{font-style: normal;padding: 0 5px;}");
        htmlStr.append("</style>");
        htmlStr.append(css.toString());
        htmlStr.append("</head><body><div style=\"width:1400px;height:1850px;\"><div style=\"background-size:100% 100%;width:100%;height:100%;background:url("+imagePath+") no-repeat\">");
        htmlStr.append("<div class=\"test\" style=\"background-color:red\"></div>");
        htmlStr.append("</body></html>");
        return htmlStr.toString();
    }

    /**
     * 獲取圖片
     * @param path 圖片路徑
     * @return
     */
    private String getThematicImageString(String path){
        InputStream inputStream = null;
        byte[] data = null;
        String classPath = this.getClass().getClassLoader().getResource("/").getPath();
        String fileNameT = path;
        String rootPathT;

        if("\\".equals(File.separator)){
            //Windows
            rootPathT = classPath.substring(1,classPath.indexOf("/WEB-INF/classes"));
            fileNameT = (rootPathT+File.separator+fileNameT).replace("/", "\\");
        }else if("/".equals(File.separator)){
            //linux
            rootPathT = classPath.substring(0,classPath.indexOf("/WEB-INF/classes"));
            fileNameT = (rootPathT+File.separator+fileNameT).replace("\\", "/");
        }

        try {
            inputStream = new FileInputStream(fileNameT);
            data = new byte[inputStream.available()];
            inputStream.read(data);
        } catch (IOException e) {
            UnitedLogger.error("加載圖片"+e.getMessage(), e);
        }finally {
            if(inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException io){
                    UnitedLogger.error("關閉流失敗"+io.getMessage(), io);
                }
            }
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return "data:image/png;base64,"+encoder.encode(data).replaceAll("\r\n","");
    }

    private void writingFile(String path,String fileText){
        FileOutputStream fos;
        BufferedWriter bw;
        try {
            fos = new FileOutputStream(path);
            bw = new BufferedWriter(new OutputStreamWriter(fos,"UTF-8"));
            bw.write(fileText);
            bw.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

conf.properties配置文件的內容

#wkhtmltopdf html+pdf temp save dir
con.report.htmlUrl=c:/temp
con.report.pdfPath=c:/temp
con.report.logoUrl=static/module/img/zxlogo.png
con.report.coverBgpUrl=static/module/img/backThematic.jpg

三、寫在後面

由於項目的保密要求,所以很抱歉不能和大家分享怎麼去讓他們相互調用,生成一份好看的報告。等到項目脫敏以後,我會把具體的調用還有目錄的動態處理一起拿出來和大家分享。

知識共享許可協議
本作品採用知識共享署名-相同方式共享 4.0 國際許可協議進行許可。

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