最近在我公司drp(運營分銷系統(tǒng))開發(fā)中,需要大量報表,由于本人有過jasperReport的開發(fā)經(jīng)驗,所以選用了它,jr確實不錯,開源,可擴展性很好,缺點就是免費的文檔很少,更可氣的是,代碼中的doc少的可憐,基本上沒有參考價值.
?????? 由于我們的產(chǎn)品是用于服裝行業(yè)的,在服裝行業(yè)有一個尺碼組,非常的麻煩,在制作含有尺碼組的報表時,表頭的各種尺碼不能寫死,要從數(shù)據(jù)庫查詢出來.但是,一般的報表工具都是不支持表頭動態(tài)化的(我理解,報表嘛,是呈現(xiàn)給特定人物如老板看的特定內(nèi)容,表頭應(yīng)該是設(shè)計好的,不會經(jīng)常性的更改),jasperReport也是一樣,并不直接支持,細究它的實現(xiàn)過程,我們還是可以擴展從而解決這個問題的.
????? 先看jasperReport的流程圖.
??
????????從上圖可看到,jrxml文件要通過JRXmlLoader解析為一個JasperDesign的對象,從源碼中可以看出,此對象用java類去描述了報表的整個設(shè)計,比如,columnHeader,detail,columnFooter等等.然后由JasperCompileManager編譯為一個JasperReport對象,其實,如果你用ireport(jasperReport報表的可視化設(shè)計器)制作報表,你完全可以不必理會怎樣生成jaserReport對象.ireport對此有很好的支持.
???????了解了以上過程,我們可以看出,如果要動態(tài)的加入設(shè)計元素,只能在JasperDesign對象中下手.加入需要的動態(tài)元素,我的需求是在columnHeader中加入一個尺碼組的表頭,代碼實現(xiàn)如下.
- package ?com.webstone.drp.report.common.dynamicHeader; ??
- ??
- import ?java.io.File; ??
- import ?java.lang.reflect.InvocationTargetException; ??
- import ?java.util.Iterator; ??
- import ?org.apache.commons.beanutils.BeanUtils; ??
- import ?net.sf.jasperreports.engine.JRException; ??
- import ?net.sf.jasperreports.engine.JasperCompileManager; ??
- import ?net.sf.jasperreports.engine.JasperReport; ??
- import ?net.sf.jasperreports.engine.design.JRDesignBand; ??
- import ?net.sf.jasperreports.engine.design.JRDesignStaticText; ??
- import ?net.sf.jasperreports.engine.design.JasperDesign; ??
- import ?net.sf.jasperreports.engine.xml.JRXmlLoader; ??
- ??
- /** ?
- ?*?@author?yaer ?
- ?*/ ??
- @SuppressWarnings ( "unchecked" ) ??
- public ? class ?ReportDesignProcess?{ ??
- ???? private ? static ? final ?String?flagTextKey?=? "customFlagText" ; ??
- ??
- ???? public ? static ?JasperReport?getJasperReport(String?xmlFilePath, ??
- ????????????String[][]?sizeGroup)? throws ?JRException?{ ??
- ????????JasperDesign?design?=?getJasperDesign(xmlFilePath); ??
- ????????JRDesignBand?columnHeader?=?(JRDesignBand)?design.getColumnHeader(); ??
- ??
- ????????reSetColumnHeaderHeight(columnHeader,?sizeGroup); ??
- ????????reSetshapeAndPosition(columnHeader,?sizeGroup); ??
- ????????addElementToColumnHeader(columnHeader,?sizeGroup); ??
- ???????? return ?JasperCompileManager.compileReport(design); ??
- ????} ??
- ???? private ? static ?JasperDesign?getJasperDesign(String?filePath) ??
- ???????????? throws ?JRException?{ ??
- ???????? return ?JRXmlLoader.load( new ?File(filePath)); ??
- ????} ??
- ???? private ? static ? void ?reSetColumnHeaderHeight(JRDesignBand?columnHeader, ??
- ????????????String[][]?sizeGroup)?{ ??
- ????????columnHeader.setHeight(columnHeader.getHeight()?*?sizeGroup.length); ??
- ????} ??
- ???? private ? static ?JRDesignStaticText?getFlagTextInDesign( ??
- ????????????JRDesignBand?columnHeader)?{ ??
- ???????? return ?(JRDesignStaticText)?columnHeader.getElementByKey(flagTextKey); ??
- ????} ??
- ???? private ? static ? void ?reSetshapeAndPosition(JRDesignBand?columnHeader, ??
- ????????????String[][]?sizeGroup)?{ ??
- ????????JRDesignStaticText?flagText?=?getFlagTextInDesign(columnHeader); ??
- ????????Iterator<jrdesignstatictext></jrdesignstatictext>?children?=?columnHeader.getChildren() ??
- ????????????????.iterator(); ??
- ????????JRDesignStaticText?element; ??
- ???????? while ?(children.hasNext())?{ ??
- ????????????element?=?children.next(); ??
- ???????????? if ?(element.getX()?>?flagText.getX())?{ ??
- ????????????????element.setX(flagText.getX()?+?flagText.getWidth() ??
- ????????????????????????*?sizeGroup[ 0 ].length); ??
- ????????????} ??
- ???????????? if ?(!flagTextKey.equals(element.getKey()))?{ ??
- ????????????????element.setHeight(element.getHeight()?*?sizeGroup.length); ??
- ????????????} ??
- ????????} ??
- ????} ??
- ???? private ? static ? void ?addElementToColumnHeader(JRDesignBand?columnHeader, ??
- ????????????String[][]?sizeGroup)?{ ??
- ????????JRDesignStaticText?flagText?=?getFlagTextInDesign(columnHeader); ??
- ????????columnHeader.removeElement(flagText); ??
- ???????? for ?( int ?i?=? 0 ;?i?<?sizeGroup.length;?i++)?{ ??
- ???????????? for ?( int ?j?=? 0 ;?j?<?sizeGroup[i].length;?j++)?{ ??
- ???????????????? try ?{ ??
- ????????????????????JRDesignStaticText?newElement?=?(JRDesignStaticText)?BeanUtils ??
- ????????????????????????????.cloneBean(flagText); ??
- ????????????????????newElement.setText(sizeGroup[i][j]); ??
- ????????????????????newElement.setX(flagText.getX()?+?flagText.getWidth()?*?j); ??
- ????????????????????newElement.setY(flagText.getY()?+?flagText.getHeight()?*?i); ??
- ????????????????????columnHeader.addElement(newElement); ??
- ????????????????}? catch ?(IllegalAccessException?e)?{ ??
- ????????????????????e.printStackTrace(); ??
- ????????????????}? catch ?(InstantiationException?e)?{ ??
- ????????????????????e.printStackTrace(); ??
- ????????????????}? catch ?(InvocationTargetException?e)?{ ??
- ????????????????????e.printStackTrace(); ??
- ????????????????}? catch ?(NoSuchMethodException?e)?{ ??
- ????????????????????e.printStackTrace(); ??
- ????????????????} ??
- ????????????} ??
- ????????} ??
- ????} ??
- }??
????? 很遺憾,沒有寫注解,原因是我看了一本書叫<<測試驅(qū)動開發(fā)>>,里面有一句話"意圖導(dǎo)向編程",意思是說,用手段比如容易理解,貼切的類名,方法名,屬性達到讓讀者輕易理解代碼.從而少寫注解,讓代碼更簡捷.如果大家不大明白以上代碼的意思,那就是我寫的不夠好,還要繼續(xù)努力.
此類只有一個方法,根據(jù)傳來的報表文件路徑和一個二維數(shù)組式的尺碼組生成一個jaserReport的對象.有三個關(guān)鍵方法.重新設(shè)置columnHeader的height;重新設(shè)置靜態(tài)內(nèi)容的形狀和大小,添加新的元素到columnHeader中,其實,這兒有一個不太容易理的東西:類中有一個flagTextKey的屬性,它是標識報表設(shè)計中動態(tài)內(nèi)容的一個樣板元素,為什么要這個樣板元素了,因為用它承載動態(tài)內(nèi)容的樣式,要比在用代碼實現(xiàn)方便的多.請看BeanUtils.coloneBean()方法,實際上是克隆樣板元素對象.
??????? 這個類設(shè)計的太具體于應(yīng)用,應(yīng)該寫成一個抽象方法,讓子類來具體實現(xiàn)加入動態(tài)元素的過程,我相信大家的需求和我不太一樣.由于時間關(guān)系,我沒有仔細考究.畢竟這只是一個參考實現(xiàn).
最后,在用于ireport畫報表時就要注意了,一呈不變的元素該怎么畫就怎么畫,但樣板元素的位置一定要放好.動態(tài)內(nèi)容起始的位置和樣式就靠它來定義,大多數(shù)時候,它是一個標簽.只不過它的"key"屬性和上面類的"flagTextKey"要保持一致.
這個話題就到這兒了,我這兒還有一個我包裝的工具類,我們公司的同事都認為對開發(fā)報表有幫助.
- package ?com.webstone.drp.report.common; ??
- ??
- import ?java.util.ArrayList; ??
- import ?java.util.Collection; ??
- import ?java.util.HashMap; ??
- import ?java.util.Map; ??
- import ?javax.servlet.http.HttpServletRequest; ??
- import ?javax.servlet.http.HttpSession; ??
- import ?javax.faces.context.FacesContext; ??
- import ?org.apache.commons.lang.ArrayUtils; ??
- import ?com.webstone.drp.report.common.dataSource.JRArrayCollectionDataSource; ??
- import ?com.webstone.drp.report.common.dynamicHeader.ReportDesignProcess; ??
- import ?net.sf.jasperreports.engine.JRException; ??
- import ?net.sf.jasperreports.engine.JasperFillManager; ??
- import ?net.sf.jasperreports.engine.JasperPrint; ??
- import ?net.sf.jasperreports.engine.JasperReport; ??
- import ?net.sf.jasperreports.engine.data.JRBeanCollectionDataSource; ??
- import ?net.sf.jasperreports.engine.JRDataSource; ??
- import ?net.sf.jasperreports.engine.util.JRLoader; ??
- ??
- /** ?
- ?*?使用jasperReport做報表時的工具支持類.有兩個用途,生成jasperPrint對象,和設(shè)置導(dǎo)出時的session ?
- ?*? ?
- ?*?@author?yaer ?
- ?*?@date?2006-8-26? ?
- ?*?@modify?date?2006-12-8 ?
- ?*/ ??
- public ? class ?ReportUtils?{ ??
- ???? public ? static ? final ?String?XLS?=? "xls" ; //?導(dǎo)出為xls文件; ??
- ???? public ? static ? final ?String?PDF?=? "pdf" ; //?導(dǎo)出為pdf文件; ??
- ???? private ? static ? final ?String?JASPER?=? "jasper" ; //?編譯過后的報表文件; ??
- ???? private ? static ? final ?String?JRXML?=? "jrxml" ; //?原始的報表文件(xml格式); ??
- ???? private ?HttpServletRequest?request; ??
- ???? private ?HttpSession?session; ??
- ???? private ?String?rootPath; //?報表文件路徑 ??
- ??
- ???? /** ?
- ?????*?在jsf環(huán)境下時構(gòu)造些工具類對象 ?
- ?????*? ?
- ?????*?@param?context ?
- ?????*????????????jsf的上下文對象 ?
- ?????*/ ??
- ??
- ???? public ?ReportUtils(FacesContext?context)?{ ??
- ????????request?=?(HttpServletRequest)?context.getExternalContext() ??
- ????????????????.getRequest(); ??
- ????????session?=?(HttpSession)?context.getExternalContext().getSession( true ); ??
- ???????? this .createRootPath(request); //?生成報表文件的絕對路徑 ??
- ????} ??
- ???? /** ?
- ?????*?在其它web環(huán)境下構(gòu)造此工具類對象 ?
- ?????*? ?
- ?????*?@param?req ?
- ?????*????????????request請求對象 ?
- ?????*/ ??
- ???? public ?ReportUtils(HttpServletRequest?req)?{ ??
- ???????? this .request?=?req; ??
- ???????? this .session?=?req.getSession(); ??
- ???????? this .createRootPath(request); //?生成報表文件的絕對路徑 ??
- ????} ??
- ???? /** ?
- ?????*?獲得報表文件的絕對路徑 ?
- ?????*? ?
- ?????*?@return?rootPath ?
- ?????*/ ??
- ???? public ?String?getRootPath()?{ ??
- ???????? return ?rootPath; ??
- ????} ??
- ???? /** ?
- ?????*?獲得JasperPrint對象;?jasperPrint對象在jasperReport中是填充了報表數(shù)據(jù)后的一個實體,打印,導(dǎo)出,顯示都要使用它. ?
- ?????*?此方法含有java5.0支持的'可變參數(shù)'特性.params其實質(zhì)是一個對象數(shù)組.在調(diào)用些方法時要注意它可能的參數(shù)順序. ?
- ?????*?此方法參數(shù)描述: ?
- ?????*?1、最多只有四個參數(shù)。 ?
- ?????*?2、固定參數(shù)filePath表示報表文件的路徑,為了支持drp系統(tǒng)中動態(tài)尺碼組做表頭的特性,?filePath包括兩類: ?
- ?????*????編譯過后的文件擴展名為'.jasper'和未編譯的原始xml文件'.jrxml'; ?
- ?????*????若報表中有動態(tài)尺碼組作表頭,則filePath為擴展名是'.jrxml'的文件。 ?
- ?????*????若報表中不涉及動態(tài)尺碼組,則filePath為擴展名是'.jasper'的文件。 ?
- ?????*?3、可變參數(shù)params的完整列表是(注意順序):Object?obj/Collection?dataSource,String?seprator,String[][]?sizeGroup. ?
- ?????*????這三個參數(shù)中,有一個例外,Object?obj/Collection?dataSource必須有一個,此參數(shù)表示填充報表的數(shù)據(jù),可以是一個Collection式的集合, ?
- ?????*????也可以是一個model對象(有且只有一個Collection的屬性); ?
- ?????*????String?seprator表示分隔符,如果數(shù)據(jù)源是一個Array的集合,則需此參數(shù)。String[][]sizeGroup表款尺碼組的二維數(shù)組。 ?
- ?????*? ?
- ?????*?@param?filePath ?
- ?????*?@param?params ?
- ?????*?@return?jasperPrint ?
- ?????*/ ??
- ???? public ?JasperPrint?getJasperPrint(String?filePath,?Object...?params)?{ ??
- ????????JasperReport?jasperReport?=? null ; ??
- ???????? try ?{ ??
- ???????????? if ?(JASPER.equals(filePath.substring(filePath.indexOf( "." )?+? 1 , ??
- ????????????????????filePath.length())))?{ //?jasper式文件的處理 ??
- ????????????????jasperReport?=?getReportTemplate(filePath); ??
- ????????????} ??
- ???????????? if ?(JRXML.equals(filePath.substring(filePath.indexOf( "." )?+? 1 , ??
- ????????????????????filePath.length())))?{ //?jrxml式文件的處理 ??
- ????????????????jasperReport?=?ReportDesignProcess.getJasperReport(filePath, ??
- ????????????????????????(String[][])?params[params.length?-? 1 ]); //?重新設(shè)置表頭,編譯 ??
- ????????????????params?=?ArrayUtils.remove(params,?params.length?-? 1 ); //?刪除參數(shù)中的sizeGroup ??
- ????????????} ??
- ???????????? return ?fillReport(jasperReport,?params); ??
- ????????}? catch ?(JRException?e)?{ ??
- ????????????e.printStackTrace(); ??
- ????????} ??
- ???????? return ? null ; ??
- ????} ??
- ???? /** ?
- ?????*?獲得JasperPrint對象;自定義填充報表時的parameter和dataSource.?參數(shù)說明和動態(tài)表頭的用法參考上一方法 ?
- ?????*?@param?filePath ?
- ?????*?@param?parameter ?
- ?????*?@param?dataSource ?
- ?????*?@param?sizeGroup ?
- ?????*?@return ?
- ?????*/ ??
- ???? public ?JasperPrint?getJasperPrint(String?filePath,?Map?parameter, ??
- ????????????JRDataSource?dataSource,?Object...?sizeGroup)?{ ??
- ????????JasperReport?jasperReport?=? null ; ??
- ???????? try ?{ ??
- ???????????? if ?(sizeGroup.length?==? 0 )?{ ??
- ????????????????jasperReport?=?getReportTemplate(filePath); ??
- ????????????} ??
- ???????????? if ?(sizeGroup.length?==? 1 )?{ ??
- ????????????????jasperReport?=?ReportDesignProcess.getJasperReport(filePath, ??
- ????????????????????????(String[][])?sizeGroup[sizeGroup.length?-? 1 ]); //?重新設(shè)置表頭,編譯 ??
- ????????????} ??
- ???????????? return ?JasperFillManager.fillReport(jasperReport,?parameter, ??
- ????????????????????dataSource); ??
- ????????}? catch ?(JRException?e)?{ ??
- ????????????e.printStackTrace(); ??
- ????????} ??
- ???????? return ? null ; ??
- ????} ??
- ???? public ? void ?setAttrToPage(JasperPrint?jasperPrint,?String?report_fileName, ??
- ????????????String?report_type)?{ ??
- ????????session.setAttribute( "REPORT_JASPERPRINT" ,?jasperPrint); ??
- ????????session.setAttribute( "REPORT_FILENAME" ,?report_fileName); ??
- ????????session.setAttribute( "REPORT_TYPE" ,?report_type); ??
- ????} ??
- ???? private ?JasperPrint?fillReport(JasperReport?jasperReport,?Object[]?params) ??
- ???????????? throws ?JRException?{ ??
- ????????Map?parameters?=? null ; ??
- ????????JRDataSource?ds?=? null ; ??
- ???????? if ?(params.length?==? 0 )?{ ??
- ???????????? return ? null ; ??
- ????????} ??
- ???????? if ?(params.length?==? 1 ?&&?params[ 0 ].getClass()?==?ArrayList. class )?{ //其實質(zhì)是要判斷是否是集合 ??
- ????????????ds?=? new ?JRBeanCollectionDataSource((Collection)?params[ 0 ]); ??
- ????????} ??
- ???????? if ?(params.length?==? 1 ?&&?params[ 0 ].getClass()?!=?ArrayList. class )?{ ??
- ????????????ClassAnalysis?ca?=? new ?ClassAnalysis(params[ 0 ]); ??
- ????????????parameters?=?ca.getFields(); ??
- ????????????ds?=? new ?JRBeanCollectionDataSource(ca.getSet()); ??
- ????????} ??
- ???????? if ?(params.length?==? 2 ?&&?params[ 0 ].getClass()?==?ArrayList. class )?{ ??
- ????????????ds?=? new ?JRArrayCollectionDataSource((Collection)?params[ 0 ], ??
- ????????????????????params[ 1 ].toString()); ??
- ????????} ??
- ???????? if ?(params.length?==? 2 ?&&?params[ 0 ].getClass()?!=?ArrayList. class )?{ ??
- ????????????ClassAnalysis?ca?=? new ?ClassAnalysis(params[ 0 ]); ??
- ????????????parameters?=?ca.getFields(); ??
- ????????????ds?=? new ?JRArrayCollectionDataSource(ca.getSet(),?params[ 1 ] ??
- ????????????????????.toString()); ??
- ????????} ??
- ???????? return ?JasperFillManager.fillReport(jasperReport, ??
- ????????????????parameters?==? null ??? new ?HashMap()?:?parameters,?ds); ??
- ????} ??
- ???? private ? void ?createRootPath(HttpServletRequest?request)?{ ??
- ????????rootPath?=?request.getSession().getServletContext().getRealPath( "/" ) ??
- ????????????????+? "WEB-INF\\classes\\com\\webstone\\drp\\report\\jaser\\" ; ??
- ????} ??
- ???? private ?JasperReport?getReportTemplate(String?jasperPath) ??
- ???????????? throws ?JRException?{ ??
- ???????? return ?(JasperReport)?JRLoader.loadObject(rootPath?+?jasperPath); ??
- ????} ??
- } ??
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
