jasperreports_JasperReports:棘手的部分
jasperreports
如果您使用Java進行編程的時間足夠長,則有可能需要為業務用戶生成報告。 就我而言,我已經看到幾個項目使用JasperReports?Library來生成PDF和其他文件格式的報告。 最近,我榮幸地觀察了Mike和他的團隊使用上述報告庫以及他們所面臨的挑戰。
簡而言之JasperReports
簡而言之,使用JasperReports(JR)生成報告涉及三個步驟:
在Java代碼中,看起來像這樣。
JasperReport compiledReport = JasperCompileManager.compileReport("sample.jrxml"); Map<String, Object> parameters = ...; java.sql.Connection connection = dataSource.getConnection(); try {JasperPrint filledReport = JasperFillManager.fillReport(compiledReport, parameters, connection);JasperExportManager.exportReportToPdf(filledReport, "report.pdf"); } finally {connection.close(); }多虧了facade類,這看起來很簡單。 但是外表可能是騙人的!
鑒于以上代碼段(以及概述的三個步驟),您認為哪些部分需要最多的時間和內存? (聽起來像面試問題)。
如果您回答(#2)填寫數據,那是對的! 如果您回答了#3,那也是正確的,因為#3與#2成正比。
恕我直言 ,大多數在線教程僅顯示簡單的部分。 在JR的情況下,似乎缺少關于較困難和棘手的部分的討論。 在這里,與Mike的團隊一起,我們遇到了兩個困難:內存不足錯誤和長期運行的報告。 使這些困難特別令人難忘的是,它們僅在生產期間出現(而不在開發期間出現)。 我希望通過共享它們,將來可以避免它們。
內存不足錯誤
第一個挑戰是報告內存不足。 在開發過程中,與實際操作數據相比,我們用于運行報告的測試數據將太小。 因此, 為此設計 。
在我們的例子中,所有報告都使用JRVirtualizer運行。 這樣,當達到內存中的頁面/對象最大數量時,它將刷新到磁盤/文件。
在此過程中,我們還了解到需要清理虛擬機。 否則,周圍會有幾個臨時文件。 而且,我們只能在報告導出到文件后清理這些臨時文件。
Map<String, Object> parameters = ...; JRVirtualizer virtualizer = new JRFileVirtualizer(100); try {parameters.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);...... filledReport = JasperFillManager.fillReport(compiledReport, parameters, ...);// cannot cleanup virtualizer at this pointJasperExportManager.exportReportToPdf(filledReport, ...); } finally {virtualizer.cleanup(); }有關更多信息,請參見Virtualizer Sample – JasperReports 。
請注意,當我們在運行報告時遇到內存不足的錯誤時,JR 并不總是罪魁禍首。 有時,即使在使用JR之前,我們也會遇到內存不足錯誤。 我們看到了如何濫用JPA來加載報告的整個數據集( Query.getResultList()和TypedQuery.getResultList() )。 同樣,由于數據集仍然很小,因此在開發期間不會顯示該錯誤。 但是,當數據集太大而無法容納在內存中時,我們會遇到內存不足錯誤。 我們選擇避免??使用JPA生成報告。 我猜我們只需要等待JPA 2.2的Query.getResultStream()可用即可。 我希望JPA的Query.getResultList()返回Iterable 。 這樣,就有可能一次映射一個實體,而不是整個結果集。
現在,避免加載整個數據集。 一次加載一個記錄。 在此過程中,我們返回了良好的JDBC。 不錯,JR很好地使用了ResultSet 。
長期運行的報告
第二個挑戰是長期運行報告。 同樣,在開發過程中可能不會發生這種情況。 充其量,將運行10秒鐘左右的報告視為冗長。 但是,有了實際的運行數據,它可以運行大約5-10分鐘。 當根據HTTP請求生成報告時,這尤其麻煩。 如果報告可以在超時時間段內(通常為60秒或最多5分鐘)開始寫入響應輸出流,那么它很有可能被請求用戶(通常是通過瀏覽器)接收。 但是,如果填寫報告需要5分鐘以上,而導出到文件又需要8分鐘,那么用戶將只會看到超時的HTTP請求,并將其記錄為錯誤。 聽起來有點熟?
請記住,報告可以運行幾分鐘。 因此, 為此設計 。
就我們而言,我們在單獨的線程上啟動報告。 對于使用HTTP請求觸發的報告,我們將以一個包含所生成報告鏈接的頁面作為響應。 這樣可以避免超時問題。 當用戶單擊此鏈接而報告尚未完成時,他/她將看到仍在生成報告。 但完成的報告時,他/她就可以看到生成的報告文件。
ExecutorService executorService = ...; ... = executorService.submit(() -> {Map<String, Object> parameters = ...;try {...... filledReport = JasperFillManager.fillReport(compiledReport, parameters, ...);JasperExportManager.exportReportToPdf(filledReport, ...);} finally {...} });我們還必須添加停止/取消運行報告的功能。 好東西,JR有檢查Thread.interrupted()代碼。 因此,僅中斷線程將使其停止。 當然,您需要編寫一些測試來進行驗證(期望JRFillInterruptedException和ExportInterruptedException )。
在討論的同時,我們重新發現了將“監聽器”添加到報告生成中的方法(例如FillListener和JRExportProgressMonitor )并為用戶提供一些進度信息。
我們還創建了實用程序測試類,以通過反復重復給定的數據來生成大量數據。 這對幫助團隊的其他成員開發專為處理長期運行和內存不足錯誤而設計的JR應用程序很有用。
進一步的設計考慮
要考慮的另一件事是填寫報告時需要打開和關閉所需的資源。 這可以是JDBC連接,Hibernate會話,JPA EntityManager或文件輸入流(例如CSV,XML)。 下圖是我的設計注意事項的粗略草圖。
1. Compiling- - - - - - - - - - - - - -\- - - -\ \ 2. Filling > open-close \- - - -/ resource > swap to file/ 3. Exporting /- - - - - - - - - - - - - -/我們想隔離#2并定義裝飾器,這些裝飾器將打開資源,填充報告并在finally塊中關閉打開的資源。 打開的資源可能取決于報表中的<queryString>元素(如果存在)。 在某些情況下,如果沒有<queryString>元素,則可能無需打開資源。
<queryString language="hql"><![CDATA[ ... ]]> </queryString> ... <queryString language="csv"><![CDATA[ ... ]]> </queryString>此外,我們還希望將#2和#3組合為一種抽象。 這種單一的抽象使通過裝飾進行裝飾變得更加容易,例如將創建的頁面對象刷新到文件中,并在導出過程中將其加載回。 如前所述,這是JRVirtualizer工作。 但是,我們希望使用結合#2和#3的抽象對對象透明的設計。
致謝
目前為止就這樣了。 再次感謝Mike和他的團隊分享了他們的經驗。 是的,他是將自己應用的收入捐贈給慈善機構的那個人 。 另外,還要感謝克萊爾(Claire)通過一次又一次重復給定數據進行測試的想法。 相關代碼段可以在GitHub上找到 。
翻譯自: https://www.javacodegeeks.com/2018/01/jasperreports-tricky-parts.html
jasperreports
總結
以上是生活随笔為你收集整理的jasperreports_JasperReports:棘手的部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jwt令牌_JWT令牌的秘密轮换
- 下一篇: 使用枚举映射_用EnumMaps映射枚举