真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

java學(xué)習(xí)之JasperReport踩坑

下面進(jìn)入正題,來介紹下今天的豬腳JasperReport或者叫它ireport亦或jasperstudio,當(dāng)然后面兩個是它的可視化工具。

創(chuàng)新互聯(lián)是專業(yè)的寶雞網(wǎng)站建設(shè)公司,寶雞接單;提供網(wǎng)站設(shè)計制作、成都網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行寶雞網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊,希望更多企業(yè)前來合作!

JasperReport是個什么東西?

這貨其實在國內(nèi)用戶也不少,是個國外的產(chǎn)品,而且可以說在JAVA報表領(lǐng)域應(yīng)用是相當(dāng)?shù)膹V泛。

我當(dāng)初剛剛接觸這個報表的時候還是相當(dāng)?shù)南矚g的,最主要的是它的可視化工具,真的是讓我欲罷不能,竟然可以通過簡單畫圖的方式來設(shè)計JAVA報表。說起畫圖就是可以通過可視化的工具,讓我們可視化的設(shè)計報表模板,并且它支持輸出的文件格式很廣泛,包括EXCEL、WORD、PDF、HTML、XML、CSV等等。

看起來是不是很強(qiáng)大,一次設(shè)計,多次復(fù)用。當(dāng)然強(qiáng)大得的東西,往往都有兩面性,這不就被我遇到了,折磨了我相當(dāng)長的時間,后文會詳細(xì)描述的。

JasperReport的大胸弟

前面我說,JasperReport或者叫它ireport或jasperstudio,其實這是不準(zhǔn)確的。二弟ireport、三弟jasperstudio其實是jasper的輔助視覺設(shè)計工具,你不用它也能設(shè)計jasper報表,多寫點XML白。5.5之前這個工具叫ireport,5.5之后隨著三弟jasperstudio的出生,ireport就被完全替代了,其實這兩個工具基本上是一樣的,一奶同胞。

具體的工作流程:

①首先Jasper會獲取需要輸出的格式信息的xml文件,然后從xml文件中編譯出.jasper類型的文件,然后這個jasper文件可以在我們的應(yīng)用程序中被加載生成最終的報表。有沒有很熟悉的感覺,是的,這一點和java很像,都需要編譯一下。

下圖,就是ireport的操作界面,jasperstudio類似,就不貼了,大家可以自行百度下。

java學(xué)習(xí)之JasperReport踩坑

上圖每種類型的band簡單介紹一下。

(1)Title band:title段只在整個報表的第一頁的最上面部分顯示,除了第一頁以外,不管報表中共有多少個頁面也不會再出現(xiàn)Title band中的內(nèi)容。

(2)pageHeader Band:顧名思義,pageHeader 段中的內(nèi)容將會在整個報表中的每一個頁面中都會出現(xiàn),顯示在位置在頁面的上部,如果是報表的第一頁,pageHeader 中的內(nèi)容將顯示在Title Band下面,除了第一頁以外的其他所有頁面中pageHeader中的內(nèi)容將在顯示在頁面的最上端。

(3)pageFooter Band:顯示在所在頁面的最下端。

(4)lastPageFooter Band:顯示在最后一頁的最下端。

(5)Detail Band:報表內(nèi)容段,在這個Band 中設(shè)計報表中需要重復(fù)出現(xiàn)的內(nèi)容,Detail 段中的內(nèi)容每頁都會出現(xiàn)。

(6)columnHeader Band:針對Detail Band的表頭段,一般情況下在這個段中畫報表的表頭。

(7)columnFooter Band:針對Detail Band的表尾段。

(8)Summary Band:表格的合計段,出現(xiàn)在整個報表的最后一頁中的Detail band 的后面,一般用來統(tǒng)計報表中某一個或某幾個字段的合計值。

上面就是可視化的工具的全部,其實怎么用很簡單,上手摸索下就會了,既然是踩坑實錄,這個自然不是重點,不說了。

代碼中的應(yīng)用

這是我總結(jié)的步驟,可能描述的不是很準(zhǔn)確,大家湊合下

①設(shè)計模板,生成JRXML文件,↑↑上面的可視化工具設(shè)計你所需要的模板樣式

②編譯模板,JRXML編譯成Jasper文件,就像java中的.java和.class文件一樣,程序中運行的需要是*.jasper的二進(jìn)制文件。

其實這一步可以直接用ireport編譯生成.jasper,當(dāng)然也可以在運行時通過jasper程序編譯。但是建議如果在程序中編譯的話,jasper版本最好和ireport或者jasperstudio的版本一致。

③執(zhí)行報表(數(shù)據(jù)填充到報表)

1、 加載模板生成Jasperreport對象

2、利用JasperFillManager,生成JasperPrint對象

④最后利用JRXlsxExporter導(dǎo)出類,將報表導(dǎo)出或者展示

加載模板

既然我們已經(jīng)利用可視化工具生成了.jasper或者.jrxml文件了,自然是需要讓程序加載它。

加載的代碼,返回jasperport對象

    if (urlPath.endsWith(".jrxml")) {
      //compile jrxml to jasper
      try {
        InputStream is = url.openStream();
        jasperReport = JasperCompileManager.compileReport(is);
      } catch (IOException e) {
        throw new BaseException("Load jasper error", e);
      } catch (JRException e) {
        throw new BaseException("The jrxml template transform to jasper file error", e);
      } catch (Throwable e) {
        log.error(e);
        throw new BaseException(e.getMessage());
      }
    } else if (urlPath.endsWith(".jasper")) {
      try {
        InputStream is = url.openStream();
        jasperReport = (JasperReport) JRLoader.loadObject(is);
      } catch (IOException e) {
        throw new BaseException("Load jasper error", e);
      } catch (JRException e) {
        throw new BaseException("The jrxml template file error", e);
      } catch (Throwable e) {
        log.error(e);
        throw new BaseException(e.getMessage());
      }
    } else {
      throw new BaseException("Invalid file!");
    }

獲取報表中的數(shù)據(jù)源

這里我采用javabean的方式獲取

      JRDataSource dataSource = null;
      if (fieldValues != null && fieldValues.size() > 0) {
        dataSource = new JRBeanCollectionDataSource(fieldValues);
      } else {
        dataSource = new JREmptyDataSource();
      }

fieldValues 為數(shù)據(jù)庫中獲取的pojo集合。

執(zhí)行報表填充

得到j(luò)asperprint對象

Map parameterValue = new HashMap();
jasperPrint = JasperFillManager.fillReport(jasperReport, parameterValue, dataSource);

最后我們利用JRXlsxExporter導(dǎo)出報表

這個也是需要配置參數(shù)最多的一個地方

baos = new ByteArrayOutputStream();
exporter = new JRXlsxExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
exporter.exportReport();

完成,數(shù)據(jù)已經(jīng)寫入輸出流中了,怎么輸出自己決定,是不是比其他方式代碼簡介很多。

確實在代碼書寫中JasperReport有著無法比擬的優(yōu)勢,各種api已經(jīng)封裝好。但是可能是恰恰做的太多,問題也不少。

JasperReport的問題

1、兩行前的空白

如果你使用上面的代碼導(dǎo)出EXCEL的話,你會發(fā)現(xiàn)Excel的背景是白色,沒了Excel一個個的小格子,這是因為jasper默認(rèn)背景為白色,這樣在導(dǎo)出其他格式時也好做到兼容,當(dāng)然當(dāng)我們導(dǎo)出EXCEL并不需要。只需要加上下面兩行就可以解決。

      //去除兩行之前的空白 
      exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS,Boolean.TRUE); 
      exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_COLUMNS,Boolean.TRUE); 
      //設(shè)置Excel表格的背景顏色為默認(rèn)的白色 
      exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND,Boolean.FALSE);

2、數(shù)據(jù)量很大,title多次寫入

如果你一個Sheet數(shù)據(jù)很多,可能會遇到表頭多次打印的情況,這種情況下,你需要加上高度設(shè)置。

Field pageHeight = JRBaseReport.class.getDeclaredField(
          "pageHeight");
      pageHeight.setAccessible(true);
      pageHeight.setInt(jasperReport, Integer.MAX_VALUE);

3、Cell的類型的問題

有時候我們導(dǎo)出的Excel報表,需要使用Excel的函數(shù)計算,如果全都是文本格式,自然計算不了,這種情況下,我們需要使用

 //自動選擇格式
 exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);

切記,在報表設(shè)計時,F(xiàn)ield字段選擇正確的類型。

4、多Sheet的問題

我上面那個簡單的例子,只是一個文件中包含一個Sheet頁,假如我們的需求是一個文件導(dǎo)出多個Sheet怎么辦,別急,這個Japser早已為我們想到了。

只需要將上文中導(dǎo)出步驟換成下面這個樣子

baos = new ByteArrayOutputStream();
exporter = new JRXlsxExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, listJasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
//設(shè)置為true,即可在一個excel中,每個單獨的jasper對象放入到一個sheet頁中
exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET,Boolean.TRUE);

JRExporterParameter.JASPER_PRINT_LIST,傳入一個listJasperPrint的集合,每個JasperPrint即一個Sheet頁。

5、Linux下啟動不報錯,但是無法導(dǎo)出報表

其實這個問題也困擾了我很久,后來在大佬的幫助下才想起來問題所在,因為它拋出的根本不是個Exception,而是Error。我看到網(wǎng)上也有同學(xué)問這個問題,所以貼出來。

可以用throwable捕獲,就可以得到錯誤信息,報錯:java.lang.InternalError: Can't connect to X11 window server using ':0.0' as

解決方法:修改tomcat/bin/catalina.sh 加JAVA_OPTS="$JAVA_OPTS  -Djava.awt.headless=true"

6、大數(shù)據(jù)內(nèi)存溢出和內(nèi)存泄露問題!!

這里需要說一下,EXCEL 03和07版的區(qū)別,03版我記得好像是只支持65532行吧,而07版之后就大的多了,具體數(shù)字我忘了,反正不是一個數(shù)量級的。

JRXlsxExporter支持導(dǎo)出xlsx文件,

JRXlsExporter則是xls的文件,很好辨認(rèn),導(dǎo)出的工具和excel的格式一樣。

然后是內(nèi)存溢出和內(nèi)存泄露問題,這個我相信玩JAVA的朋友基本上都遇到過。

關(guān)于內(nèi)存溢出最通常的解決辦法便是增大容器的內(nèi)存,增加tomcat的內(nèi)存大小,方法大家可以百度,有很多,不重復(fù)造輪子了。

這里提醒下,如果你使用的是tomcat的話,windows安裝版,解壓縮版和Linux版的配置方式都是不同的,需要注意下。

這里我需要介紹的是JasperReport的方式,其實JasperReport是對大數(shù)據(jù)有解決方案的,在很早期的版本便推出了,JRFileVirtualizer的仿真器。

這個東西是做啥用的呢,其實它會根據(jù)你設(shè)置的參數(shù),將數(shù)據(jù)寫到硬盤的臨時文件上,這樣解決了填充報表時內(nèi)存占用過大溢出的問題。

目前JasperReport有3個仿真器,都是用來解決這個問題的。

分別是:

①JRFileVirtualizer

②JRSwapFileVirtualizer

③JRGzipVirtualizer

這三個仿真器又有什么區(qū)別呢?

首先是推出最早的JRFileVirtualizer,我在測試時,當(dāng)導(dǎo)出30W左右的數(shù)據(jù),就會報內(nèi)存溢出,后來加上這個后就可以正常導(dǎo)出了。這個仿真器會把每一個對象生成一個臨時文件存放在硬盤上解決內(nèi)存占用的問題,但是因為產(chǎn)生的臨時文件較多,無形中增加了文件創(chuàng)建和刪除的內(nèi)存消耗,所以并不是很推薦。

//寫多個文件
 JRFileVirtualizer virtualizer = new JRFileVirtualizer(2, catchPath);
 Map parameterValue = new HashMap();
 parameterValue.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
virtualizer.setReadOnly(true);

catchPath為文件緩存路徑,必須真實存在,否則會報錯。

然后是JRSwapFileVirtualizer,這個是為了解決JRFileVirtualizer的問題而推出的。這個仿真器,只會創(chuàng)建一個臨時文件,每個對象會占這個文件的一部分,所以就減少的文件創(chuàng)建和刪除的內(nèi)存消耗,其實這個也不是特別推薦。

//寫單個文件
RSwapFile arquivoSwap = new JRSwapFile(catchPath, 4096, 25);
JRAbstractLRUVirtualizer virtualizer = new JRSwapFileVirtualizer(2, arquivoSwap, true);
    
Map parameterValue = new HashMap();
parameterValue.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
virtualizer.setReadOnly(true);

最后是JRGzipVirtualizer這個,看到Gzip,不知道你是否有聯(lián)系到壓縮這個詞匯。沒錯,這個仿真器就是使用一種特殊的壓縮算法,可以將內(nèi)存占用壓縮到二十分之一還是十分之一來著,總之很神奇。

JRAbstractLRUVirtualizer virtualizer = new JRGzipVirtualizer(2);
Map parameterValue = new HashMap();
parameterValue.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
jasperPrint = JasperFillManager.fillReport(jasperReport, parameterValue, dataSource);

說了這么多,總之就是三種仿真器解決內(nèi)存溢出問題,我也看了很多博客里面寫利用JRFileVirtualizer,解決內(nèi)存大數(shù)據(jù)問題。然后我在這里想說,我最最最不推薦使用JRFileVirtualizer仿真器,因為它不僅創(chuàng)建文件消耗大,還有個很嚴(yán)重的BUG,內(nèi)存泄露!??!還有JRSwapFileVirtualizer也有這個問題。

另外,需要說明的是不使用仿真器,也會有內(nèi)存泄露的問題,當(dāng)你導(dǎo)出報表后,dump出堆棧信息,會發(fā)現(xiàn)net.sf.jasperreports.engine.fill.JRTemplatePrintText類的實例特別多,無法回收,無法回收?。?!并且最新版的japserreport 6.x依舊存在這個問題,在jasper的社區(qū)和Stack Overflow存在很多這樣的問題,而沒有解決方案。

這里推薦JRGzipVirtualizer仿真器,雖然依舊存在泄露問題,但是因為獨特的壓縮算法,已經(jīng)將內(nèi)存泄露問題控制在很小的范圍里了,算是一種緩解的方案吧,大概泄露的內(nèi)存占用緩解了九成以上。

總的來說,我現(xiàn)在已經(jīng)放棄這種方案了,寫出來也是為了后來的兄弟少走彎路。擼了一個POI的工具類,接下來準(zhǔn)備把所有的報表改成POI導(dǎo)出的方式,話說POI的大數(shù)據(jù)方案還是挺不錯的。


本文名稱:java學(xué)習(xí)之JasperReport踩坑
當(dāng)前路徑:http://weahome.cn/article/pcssge.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部