在 Struts 中結合 JFreeChart,iText 生成 PDF 報表

jopen 12年前發布 | 65K 次閱讀 iText PDF工具包

本文中向讀者朋友提供了一種 PDF 報表系統的解決方案,并將重點放在如何整合開源框架以實現系統要求,以及如何解決實際開發過程中的疑難問題上,對于廣大的開源框架愛好者和開發人員具有一定的借鑒意義。該報表解決方案主要提供以下功能:

  1. 用戶圖片上傳
  2. 根據數據生成柱狀圖,折線圖
  3. 匯總數據及圖片,最終以 PDF 進行呈現

開源框架整合

基于對開源領域中比較成熟的框架的比較,我們最終選擇以 Struts 為基礎,整合 common-fileupload,JFreechart 和 iText,以實現上述的系統功能。下面我們來講述如何整合這些開源框架,建立開發環境。

Struts

Struts(http://struts.apache.org/) 是廣泛使用的 MVC 框架,相信很多開發人員都非常熟悉,這不是本文的重點,僅會提及一個技術點,即如何在 Struts 框架中實現文件上傳,將在下文中詳細描述。

Commons-fileupload

Commons-fileupload (http://commons.apache.org/fileupload/) 能與 Servlet 及 Web application 很好地結合,基于對 Http request 的解析,可以被方便靈活地調用,從而提供高性能的文件上傳功能。

JFreeChart

JFreeChart(http://www.jfree.org/) 主要是用來制作各種各樣的圖表,包括:餅圖、柱狀圖 ( 普通柱狀圖以及堆棧柱狀圖 )、線圖、區域圖、分布圖、混合圖、甘特圖以及一些儀表盤等等。本文中使用的是 jfreechart-1.0.13.jar。

iText

iText(http://itextpdf.com/) 是一個能夠快速產生 PDF 文件的 Java 類庫,與 Servlet 有很好的給合,可以非常方便完成 PDF 輸出,最新的版本是 iText-5.0.4.jar。如果需要在報表中支持中文顯示,還需要下載 iTextAsian.jar。

Eclipse 中整合開源框架

為完成開發框架的搭建工作,我們需要將上述的幾個開源框架整合到 Eclipse 中。讀者需要通過以上的鏈接下載相應的各個 Jar 包,然后導入到工程的類路徑下。可以參考 Eclipse 的相關資料來完成這些配置操作。

Struts 中的文件上傳

基于 Struts 框架實現文件上傳需要注意以下兩點:

  1. Form 需要增加屬性: enctype="multipart/form-data"。
    如:<form method="post" id="reportForm" enctype="multipart/form-data">
  2. 需要直接繼承自 Action,而不能是 DispatchAction。

以上兩點需要在開發過程中加以注意,否則使用 ServletFileUpload 的 parseRequest() 方法解析 request 的時候,得不到 Form 中 file 域傳遞的值。JSP 頁面的代碼在這里不再贅述,下面通過代碼及注釋來說明 Commons-fileupload 的使用,讀者可以根據實際需要設定上傳圖片的保存路徑和文件的名稱。


清單 1. 使用 Commons-fileupload 上傳文件


DiskFileItemFactory factory = new DiskFileItemFactory(); // 實例化硬盤文件工廠 factory.setSizeThreshold(8192);// 存放臨時文件的內存大小 String tempPath = request.getRealPath("/") + "/images/temp"; if(!new File(tempPath).isDirectory()) new File(tempPath).mkdirs(); factory.setRepository(new File(tempPath));

// 設置上傳路徑 uploadPath = request.getRealPath("/") + "/web/report/images/"; if(!new File(uploadPath).isDirectory()) new File(uploadPath).mkdirs();

// 初始化上傳組件,循環 form 中的所有 input 類型為 file 的 field,上傳文件 ServletFileUpload upload = new ServletFileUpload(factory); List<FileItem> items = upload.parseRequest(request);
Iterator<FileItem> itr = items.iterator(); while (itr.hasNext()) {// 依次處理每個 form field FileItem item = (FileItem) itr.next(); File savedFile = new File(uploadPath, "imageFileName.jpg"); item.write(savedFile); } </pre>

JFreechart 生成報表

最新的 struts 2.0 已經集成了 JFreechart,作為一種 ResultType 在 Action 中可以直接返回,讀者如果感興趣可以參考其他相關的資源。本文中我們介紹如何基于 Struts 1.x 版本來集成使用 JFreechart。

生成圖片報表

這里我們封裝了一個實用類 ChartUtil,它繼承自 JFreeChart 的 ServletUtilities 類,來提供本文所述報表方案的所有生成 JFreechart 報表的功能。清單 2 中給出了如何生成一個柱狀圖的方法,該方法的調用將會在清單 6 中看到。


清單 2. 封裝 JFreechart 的 util 類,生成柱狀圖


  • public static String generateBarChart(HttpServletRequest request, CategoryDataset dataset, int w, int h,double rangeMarker) throws IOException { JFreeChart chart = ChartFactory.createBarChart3D("Latency in ms", // 圖表標題 "Time", // 目錄軸的顯示標簽 "Milliseconds", // 數值軸的顯示標簽 dataset, // 數據集 PlotOrientation.VERTICAL, // 圖表方向:水平、垂直 true, // 是否顯示圖例 ( 對于簡單的柱狀圖必須是 false) false, // 是否生成工具 false // 是否生成 URL 鏈接 ); setAttribute(chart);

        createTempDir(request); 
    
        chart.getCategoryPlot().addRangeMarker(new ValueMarker(rangeMarker)); 
    
        String tempDirName = request.getRealPath("/") + "/web/report/images/temp/"; 
    
        String prefix = ServletUtilities.getTempFilePrefix(); 
        if (request.getSession() == null) { 
            prefix = ServletUtilities.getTempOneTimeFilePrefix(); 
        } 
    
        File tempFile = File.createTempFile(prefix, ".png", 
                new File(tempDirName)); 
        try { 
            ChartRenderingInfo info = new ChartRenderingInfo( 
                    new StandardEntityCollection()); 
    
            ChartUtilities.saveChartAsPNG(tempFile, chart, w, h, info); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
        return tempDirName + tempFile.getName(); 
    } </pre></td> 
    </tr> 
    

    </tbody> </table>

     

    修改默認圖片保存路徑

    JFreeChart 默認將生成的圖片保存在應用服務器的 temp 目錄下,有些時候,我們不能使用默認的保存路徑,而是需要能夠再次通過應用程序讀取這些圖片,這時就需要將圖片保存在應用程序的目錄下。下面,我們將介紹 如何實現對默認圖片保存路徑的修改,即在 ChartUtil 類中重寫 createTempDir 方法,將圖片保存在應用程序的 /web/report/images/temp 目錄下。


    清單 3. 重寫 createTempDir 方法


    protected static void createTempDir(HttpServletRequest request) { String tempDirName = request.getRealPath("/") + "/web/report/images/temp"; if (tempDirName == null) { throw new RuntimeException("Temp directory is null."); }

        File tempDir = new File(tempDirName); 
        if (!tempDir.exists()) { 
            tempDir.mkdirs(); 
        } 
    } </pre></td> 
    </tr> 
    

    </tbody> </table>

     

    如何定制圖片樣式

    JFreeChart 提供了對圖片格式修改的各種 API,包括對圖片背景,文字顯示,曲線,坐標等等一系列的格式設置,讀者可以根據實際需要查詢相應的 API 來實現。比如,上面的清單 2 中,我們有如下一行代碼,實現了在柱狀圖中增加一條閾值線。

    清單 4. 柱狀圖中增加閾值線

                 
     chart.getCategoryPlot().addRangeMarker(new ValueMarker(rangeMarker)); 

    iText 生成 PDF 報表

    iText 是一個 Java 類庫,可以方便地創建,讀取和操作 PDF 文件。下面我們通過一個最簡單的例子來說明如何使用 iText。然后重點介紹一下幾個比較重要的 object,并針對最常見的使用過程中遇到的問題給出一些建議。


    清單 5. iText 的簡單使用


  • //set pdf location and the title String pdfLocation = request.getRealPath("/") + "/web/report/pdf/"; String pdfName= "test.pdf"; String pdfFile = pdfLocation + pdfName;

    Document document = new Document(); try { PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(pdfFile)); document.open(); document.add(new Paragraph("Hello world")); } catch (DocumentException de) { System.err.println(de.getMessage()); } catch (IOException ioe) { System.err.println(ioe.getMessage()); } finally { document.close(); } </pre></td> </tr> </tbody> </table>

     

    iText 結構概覽

    從上面的代碼片段中,我們可以看到 Document 對象是 iText 的基礎,從 open,add,close 的調用過程,我們也可以很容易理解 iText 的使用。

    iText 對于對象的組織,也是像實際的 PDF 文件中一樣,是一種分級結構。Chunk(塊)是 iText 中最小也是最重要的可以被加入到 Document 中的文本塊,絕大部分的元素都可以被分割成 Chunk。Phrase 由一個或多個 Chunk 組成,它有一個主字體樣式,同時包含在其中的 Chunk 可以通過設置使用不同于 Phrase 的其他字體樣式。

    下面我們通過代碼片段來看看如何將圖片寫入到 PDF 文件中,其實,這與寫入普通的文本并沒有實質區別。我們通過 dataService 獲取生成 JFreeChart 的數據集,然后調用 ChartUtil 生成圖片并返回圖片文件的路徑及名稱,進而得到一個 com.itextpdf.text.Image 對象,將它增加到一個 PdfPTable 中寫入 PDF。


    清單 6. 用 iText 將 JFreechart 圖表寫入 PDF


    // 初始化一個 PdfPTable PdfPTable BarTable = new PdfPTable(1); PdfPCell cellDescription = new PdfPCell(new Paragraph("This is a image from JFreechart")); cellDescription .setBorder(PdfPCell.NO_BORDER); BarTable.addCell(cellDescription );

    // 生成柱狀圖 CategoryDataset latencyDataset = dataService.getLatencyDataset(nodeA, nodeB, month); String fileName = ChartUtil.generateBarChart(request, latencyDataset, 500, 200,link.getLatency()); Image imageLatency = Image.getInstance(fileName);

    // 加到 table 中 PdfPCell cellImageLatency = new PdfPCell(imageLatency); cellImageLatency.setBorder(PdfPCell.NO_BORDER); cellImageLatency.setHorizontalAlignment(Element.ALIGN_CENTER); BarTable.addCell(cellImageLatency);

    // 生成曲線圖 CategoryDataset lossDataset = dataService.getLossDataset(nodeA, nodeB, month); fileName = ChartUtil.generateLineChart(request, lossDataset, 500, 200); Image imageLoss = Image.getInstance(fileName); // 加到 table 中 PdfPCell cellImageLoss = new PdfPCell(imageLoss); cellImageLoss.setBorder(PdfPCell.NO_BORDER); BarTable.addCell(cellImageLoss); // 寫入 PDF document.add(BarTable); </pre></td> </tr> </tbody> </table>

     

    iText 支持中文

    為了讓 iText 支持中文,我們需要下載語言包并加入到類路徑中。最新的 iText-5.0.4.jar 對包結構進行了更改,由 com.lowagie.text.pdf.fonts 更新為 com.itextpdf.text.pdf.fonts,但是 iTextAsian.jar 依舊是沿用舊的包結構,因此我們需要修改 iTextAsian.jar 的包的結構,才能正確支持中文。


    清單 7. iText 中如何支持中文字體

     BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", 
     BaseFont.NOT_EMBEDDED); 
     Font chineseFont= new Font(bfChinese, 12, Font.NORMAL);   
     PdfPCell cellReportSummary = newPdfPCell(newPhrase("支持中文",chineseFont)); 

     本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
     轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
     本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
  • sesese色