自動把動態的jsp頁面(或靜態html)生成PDF文檔,並且上傳至服務器

這幾天,任務中有一個難點是把一個打印頁面自動給生成PDF文檔,並且上傳至服務器,然而公司框架只有手動上傳文檔,打印時可以保存爲PDF在本地吧,所以感到很頭疼,剛開始沒有方向,所以只有surf the Internet了,網上看了很多資料,漸漸的從一點方向也不懂,到慢慢開始瞭解怎麼着手去做,廢話就不說了,

我看網上大概介紹了三種方式:Jasper Report 、 iText 、 flying sauser  

jasper report和flying sauser感覺上要比iText的實現要強大一點,但是我實際用的時候對CSS沒有太大的需求,因爲是一個很簡單的表格形式,(如果對pdf的樣式有很高的要求,可以去看看flying sauser,這東西能解析HTML和CSS,而且能輸出成image,PDF等格式),我用的則是iText,我用的jar是:

itext-asian-5.2.0、itextpdf-5.5.1、xmlworker-5.5.4、jsoup-1.10.2(此包是java的html解析器)

1、自動生成PDF,

下面CreatePdfDocument.javaAsianFontProvider.java是兩個工具類,AsianFontProvider 是在CreatePdfDocument裏面調用的,而CreatePdfDocument則會在待會兒的實現裏面調用。

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.jsoup.Jsoup;

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;

/**
 * Created by Sinoprof Codeproducer
 * User: ck
 * Date: 2017-10-31
 * Time: 09:25:06
 * 實現生成PDF文件
 */

public class CreatePdfDocument {

    /**
     * 根據URL提前blog的基本信息,返回結果
     * @param URL 例:http://localhost:8080/scm/scm/po/gather/pdftest/pdftesthtml3.html(能直接返回某個html的URL,
     *            我開始傳url時候被struts1攔截了,應爲get不到session的登錄人信息,所以得到的是登錄頁面的html)
     * @return
     * @throws Exception
     */
    public static  String[] extractHtmlInfo(String URL) throws Exception {
        /*這裏爲什麼用數組,是因爲返回的時候不僅可以返回選擇的html,
        還有從document提取其他的信息單獨存在數組裏返回,然後利用iText在pdf裏面組裝數據,可以在網上查*/
        String[] info = new String[1];
        // 直接把URL解析成document,然後調用document.html()解析爲html
        org.jsoup.nodes.Document doc = Jsoup.connect(URL).get();
        // 此doc.select是用來選擇完整的html中某一部分這裏爲第一個div的css爲entry的部分,所以你的html上要有div的class爲entry哦
        org.jsoup.nodes.Element entry = doc.select("div.entry").first();
        info[0] = entry.html();
        return info;
    }

    /**
     * 直接通過得到html來取得想要的部分html
     * @param html
     * @return
     * @throws Exception
     */
    public static  String[] extractHtmlInfo2(String html) throws Exception {
        String[] info = new String[1];
        // 把html轉換爲document
        org.jsoup.nodes.Document doc = Jsoup.parse(html);
        // 此doc.select是用來選擇完整的html中某一部分這裏爲第一個div的css爲entry的部分,所以你的html上要有div的class爲entry哦
        org.jsoup.nodes.Element entry = doc.select("div.entry").first();
        info[0] = entry.html();
        return info;
    }

    /**
     * 把String 轉爲 InputStream
     * @param content
     * @return
     */
    public static InputStream parse2Stream(String content) {
        try {
            ByteArrayInputStream stream = new ByteArrayInputStream(
                    content.getBytes("GBK"));
            return stream;
        } catch (Exception e) {

            return null;
        }
    }


    /**
     * 直接把網頁內容轉爲PDF文件
     *
     * @param
     * @throws Exception
     */
    public static String parseURL2PDFFile(String pdfFile, String html) {
        String returnVal = "";
        try {
            BaseFont bfCN = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H",
                    false);
            // 中文字體定義
            Font chFont = new Font(bfCN, 14, Font.NORMAL, BaseColor.BLUE);
            Font secFont = new Font(bfCN, 12, Font.NORMAL, new BaseColor(0, 204,
                    255));
            Font textFont = new Font(bfCN, 12, Font.NORMAL, BaseColor.BLACK);

            Document document = new Document(PageSize.A4);
            // 設置pdf的背景圖片
            Image image = Image.getInstance("D:/移動背景圖片.jpg");
            image.setAlignment(image.UNDERLYING);
            image.setAbsolutePosition(0,0);
            image.scaleAbsolute(595,842);

            PdfWriter pdfwriter = PdfWriter.getInstance(document,
                    new FileOutputStream(pdfFile));
            pdfwriter.setViewerPreferences(PdfWriter.HideToolbar);
            document.open();
            document.add(image);
            //得到解析的html
            String[] blogInfo = extractHtmlInfo2(html);
        /*html文件轉換爲pdf文檔
        AsianFontProvider()函數是用來解決XMLWorkerHelper.getInstance().parseXHtml()轉pdf中文不顯示問題*/
            XMLWorkerHelper.getInstance().parseXHtml(pdfwriter, document,parse2Stream(blogInfo[0]),null, new AsianFontProvider());

            document.close();
            returnVal = "YES";
        } catch (Exception e) {
            returnVal = "NO";
            e.printStackTrace();
        } finally {
            return returnVal;
        }
    }
}

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;

/**
 * Created by Sinoprof Codeproducer
 * User: ck
 * Date: 2017-10-31
 * Time: 09:25:06
 * 用來解決XMLWorkerHelper.getInstance().parseXHtml()轉pdf中文不顯示問題
 */
public class AsianFontProvider extends XMLWorkerFontProvider{

    public Font getFont(final String fontname, final String encoding,
                        final boolean embedded, final float size, final int style,
                        final BaseColor color) {
        BaseFont bf = null;
        try {
            bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Font font = new Font(bf, size, style, color);
        font.setColor(color);
        return font;
    }
}




 下面時調用生成PDF,我就隨便寫了個main方法,注意不要直接引用下面這段代碼哦,這是兩種情況,選一種來試試
/**
 * @param args
 */
public static void main(String[] args) throws Exception {
    // 網頁必須是可以直接訪問的URL,
    String blogURL = "http://localhost:8080/scm/scm/po/gather/pdftest/pdftesthtml3.html";
    // 傳入自己的html,注意html要符合w3c的標準html,因爲itexthtml格式有點嚴格,
    String html = "";
    // PDF最後的輸出文檔,注意d:/test/itext這些folder要先建好
    String pdfFile = "d:/test/itext/demo-URL.pdf";
    // 直接把網頁內容轉爲PDF文件 但是這個網頁必須是可以直接訪問的URL,注意在CreatePdfDocument.javaparseURL2PDFFile方法中要調用extractHtmlInfo方法
    Demo4URL2PDF.parseURL2PDFFile(pdfFile, blogURL);
    // 直接傳入html的,注意在CreatePdfDocument.javaparseURL2PDFFile方法中要調用extractHtmlInfo2方法
    Demo4URL2PDF.parseURL2PDFFile(pdfFile, html);
}

這樣子基本就能在你指定的位置生成PDF文檔了,但注意前面說過iText對html的樣式支持的很少,所以生成的pdf文檔比較簡單,jtext-asian-5.2.0、itextpdf-5.5.1、xmlworker-5.5.4,這三個jar是我在網上找的支持table標籤的,(剛開始找的低版本的jar不支持table,所以我的表格出不來),還有就是AsianFontProvider.java這個類對中文的支持,因爲iText的XMLWorkerHelper.getInstance().parseXHtml轉PDF的時候,中文不顯示,

(網上說是什麼沒有默認的中文字體,我看網上有人修改xmlworker源碼的,使其默認一個字體),

但是我沒有成功,機緣巧合之下我找到了這種不用修改源碼的就像這樣

XMLWorkerHelper.getInstance().parseXHtml(pdfwriter,document,parse2Stream(blogInfo[0]),null,newAsianFontProvider());

剛好能幫我解決我的需求,結果圖片如下:



下面說說任務中的遇到的困難,上面說自動生成PDF時可以直接傳入string類型的html或者URL,但這個URL要是課可以直接訪問的,比如說網頁的網址,但是我們的項目中有struts1會攔截沒有登陸的,沒有登陸就會跳轉到登錄頁面,所以每次我用URL的去測試的時候,返回的始終是一個登錄頁面的html,其實我需要的就是一個動態的jsp生成PDF。

剛好,又讓我找到了現成的方法,其實原理是:得到數據後,讓jsp頁面不輸在瀏覽器上顯示,而是輸出到字節流最後以字符的形式返回,這樣我就可以得到動態的jsp組裝好後輸出的靜態的html,這樣就得到了我想要的html。

具體的我直接po博主的博客吧http://www.cnblogs.com/Iran1112/p/6013474.html,這裏面我學習了怎麼讓動態的jsp以流的方式輸出html。


至於上傳至服務器,要看看自己服務器要怎麼存儲了,一般的思路:先讀寫文件比如這樣:

// 輸入流
FileInputStream fi = new FileInputStream(fPath);
BufferedInputStream bi = new BufferedInputStream(fi);
// 輸出流
FileOutputStream fo = new FileOutputStream(newFile);
BufferedOutputStream bo = new BufferedOutputStream(fo);
// 先定義一個字節緩衝區,減少I/O次數,提高讀寫效率
byte[] buf = new byte[1024];
int len = 0;
while ((len=bi.read(buf))!=-1){
    bo.write(buf,0,len);
    // 使緩衝的輸出字節 被寫到底層輸出流中 避免電腦斷電等特殊情況導致緩衝區中的數據被清空
    bo.flush();
}
fi.close();
fo.close();
然後拿到文件的信息,比如說:文件名稱、存儲路徑、大小...,再insert(存入)自己的表裏面,基本上大概就是這樣。

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