1. 程式人生 > >利用jasperReport製作web報表

利用jasperReport製作web報表

       作者:54dabang

                                E-mail:[email protected]

一 前言

     一直髮現在網上尋找資源比較繁瑣,前段時間在製作jasperReport報表時候出現了很多問題。特別是在一些細節方面,特別耗費時間。特此寫下此文,希望對和我一樣在初期階段學習的同學能少走一些彎路。

二 內容簡介

     1)給出自己製作的jasperReport的檢視效果,方便對報表工具初期學習的選擇。

     2)自己製作報表的測試原始碼和所有相關學習資料,對應所有jar包,jasperReport版本。

     3)快速開發報表的一些建議,為方便學習者快速開發,本文特封裝了通用介面。

     4)在linux下部署jasperReport出現記憶體溢位的問題解決方案。

三  jasperReport的檢視效果

    

    


 JasperReport支援多種資料格式匯出,包括excelpdfRTFJXLODFhtml等。如果在web頁面使用我推薦將pdf格式檔案嵌入到iframe當中,原因是視覺效果好,只要客戶端安裝了pdfReader即可在頁面上進行列印、預覽、儲存等操作。

四  相關資料與測試原始碼

這個部落格講了以 實現JRDataSource介面為資料來源,從構造實體類到匯出報表的所有過程,而且十分易於上手,並且提供了原始碼。我的專案本身也是在此基礎上完成的。強烈推薦一下。由於他的專案中存在jar

包不全的問題,可以直接下載我的測試專案。需要注意的是我的Ireport版本為3.5.2。最好下載對應版本,否則由於jar包不一致,可能會出現匯出報表錯誤,這裡我給出對應的3.5.2版本的百度雲盤工具連結:百度雲盤iReport工具連結

我的完整測試例子(重要)下載連結:

JaperReport官網:

japerReport API(英文版)

jasperReport各種文件大全(自己收集)含:JasperReport中文使用者手冊 jaspersoft-studio-user-guide_0.pdf Jasper_+_ireport_整合報表到Web應用_操作說明.doc

iReport中文教程.doc JasperReport+iReport報表工具詳細開發手冊.doc等。

下載連結  http://download.csdn.net/detail/leixingbang1989/8545885

jasperReport

前臺頁面:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%
        String path = request.getContextPath();
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
        
%>
<html>

    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <link rel="stylesheet" type = "text/css"  href ="extjs/resources/css/ext-all.css">
       <link rel="stylesheet" type="text/css" href="css/ext-input.css">
       <script type ="text/javascript" src="extjs/adapter/ext/ext-base.js"> </script>
        <script type ="text/javascript" src="extjs/ext-all.js"></script>
        <script type="text/javascript" src="extjs/resources/js/ext-lang-zh_CN.js"></script>
        
       
        <title>測試頁面程式</title>
    </head>
    <script type="text/javascript">
    
  Ext.onReady(function(){
         Ext.useShims=true;//一定要加上這句 否則會出現日期的panel被iframe覆蓋
         var startdate = new Ext.form.DateField({
             fieldLabel: '開始時間',
             labelStyle : "text-align:right;",
             id:"awardstartdate",
             name: 'startdate',
             width: 100,
             maxValue:new Date(),
             allowBlank: false, // 設定非空,
             altFormats: 'Y-m-d ',
             format: 'Y-m-d ',
             listeners: {
                 'select' : function() {
                     var start = Ext.getCmp('awardstartdate').getValue();
                     Ext.getCmp('awardenddate').setMinValue(start);
                     var endDate = Ext.getCmp('awardenddate').getValue();
                     if(start > endDate){
                         Ext.getCmp('awardendDate').setValue(start);
                     }

                 }
             },
             blankText: 'rrr ...', //如為空,後面會出現一個I的圖示,點選後出現的alt內容
             value:Date.parseDate('1990-01-01','Y-m-d') //如為空,直接在input中出現的text,有紅色邊框
         });
         var enddate = new Ext.form.DateField({
             fieldLabel: '結束時間',
             labelStyle : "text-align:right;",
             id:"awardenddate",
             name: 'enddate',
             width: 100,
             minValue:Date.parseDate('1990-01-01','Y-m-d'),
             allowBlank: false, // 設定非空,
             altFormats: 'Y-m-d ',
             format: 'Y-m-d ',
             listeners: {
                 'select' : function() {
                     var end = Ext.getCmp('awardenddate').getValue();
                     Ext.getCmp('awardstartdate').setMaxValue(end);
                     var startDate = Ext.getCmp('awardstartdate').getValue();
                     if(end < startDate){
                         Ext.getCmp('awardstartDate').setValue(end);
                     }

                 }
             },
             blankText: 'rrr ...', //如為空,後面會出現一個I的圖示,點選後出現的alt內容
             value: new Date() //如為空,直接在input中出現的text,有紅色邊框
         });
         var f=new Ext.form.FormPanel({
             id:"awardqueryForm",
             method:"post",
             frame:true,
             renderTo:"researchAward",
             items:[{
                     //layout:"column",
                      layout: {
                           type: 'column',
                           pack: 'center',             
                           //縱向對齊方式 start:從頂部;center:從中部;end:從底部
                           align: 'left'            
                          //對齊方式 center、left、right:居中、左對齊、右對齊;stretch:延伸;stretchmax:以最大的元素為標準延伸
                          },
                     items:[{layout:"form",columnWidth:.15,items:[startdate]},
                            {layout:"form",columnWidth:.15,items:[enddate]}
                          ]
                 }],
            buttons:[
                 {
                     text:"確定",
                     handler:function(){
                	 change();
                               }
                 }],
                 renderTo:"researchDiv"
         }
         );
                 
	  var gasReportPanel1 = new Ext.Panel({
			id:"gasReportPanel1",
			//height : 800,
			autoHeight: true,
			html : "<iframe  id='myIframe'  frameborder='1' src='PDFServlet' width='800px' height='1000px'></iframe>",
			region : 'center',
			renderTo:"researchDiv",
			listeners: {
		        afterrender: function() {//渲染完成後
		     
		       }
			}
		});
    });
    var i=0;
    function change()//通過javascript來控制iframe的資料來源,我這裡只做演示
    {
    
        i++;
        alert(i);
        var result=i%2;
        var ifm= document.getElementById("myIframe");
        if(result==0)
        {
        	ifm.src="jsp/viewer.jsp"; //引數可以通過url路徑傳入
        	
        }else
        {
        	ifm.src="PDFTest"; 
        }
        setIframeHeight("myIframe");
    
        
    }
   
 
      
    </script>
  <body>
 <div id="researchDiv" name="researchDiv" align="center"></div>
  <div align="center" id="frameDiv" name="frameDiv"></div>
  </body>
</html>

後臺程式:

package com.mengya.servlet;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.util.FileBufferedOutputStream;
import net.sf.jasperreports.engine.util.JRLoader;

import com.jasperReport.dataSource.HorizontalProjectsDataSource;
import com.jasperReport.dataSource.PortraitResearchProjectStatusDataSource;
import com.jasperReport.dataSource.UiniversityKnowlegeStatusDataSource;
import com.jasperReport.dataSource.UniversityAcademyDataSource;
import com.jasperReport.dataSource.UniversityPrizeDataSource;
import com.jasperReport.dataSource.noSource;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;
import com.mengya.JRDataSource.PersonDataSource;

public class PDFTest  extends HttpServlet {
	private ServletContext servletContext;
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doPost(request, response);
	}
   private String getRealRealPath(String sourceJapser)//封裝獲取在web中獲取檔案路徑的方法
   {
	  String basePath="/myJasper/";
	  return this.servletContext.getRealPath(basePath+sourceJapser);
   }
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		
		this.servletContext= this.getServletConfig()
				.getServletContext();
		
		File jasperFile = new File(this.getRealRealPath("NCUTtechBulletin.jasper"));//獲取檔案
		 Map map=new HashMap();
	        map.put("startDate", "1990-01-01");
		  	map.put("endDate","2001-01-01");
		  	map.put("subReportUniverstiyACds", new UniversityAcademyDataSource());//學術成果資料來源
		  	map.put("subReportUniverstiyACDir",this.getRealRealPath("UniversityAcademyStatus.jasper"));//學術成果jasper路徑
		  	
		  	map.put("subReportPrizeDS", new UniversityPrizeDataSource ());//科研獲獎資料來源
		  	map.put("subReportPrizeDir",this.getRealRealPath("UniversityPrizeStatus.jasper"));//科研獲獎jasper路徑
		  	
		  	map.put("subReportKnowlegeDS", new  UiniversityKnowlegeStatusDataSource ());//智慧財產權資料來源
		  	map.put("subReportKnowlegeDir",this.getRealRealPath("UiniversityKnowlegeStatus.jasper"));//智慧財產權jasper路徑
		  	
			map.put("subReportPortraitRPds", new  PortraitResearchProjectStatusDataSource ());//縱向專案資料來源
		  	map.put("subReportPortraitRPdir",this.getRealRealPath("UniversityPortraitResearchProjectStatus.jasper"));//縱向專案jasper路徑
		  	
		  	map.put("subReportHorizontalRPds", new  HorizontalProjectsDataSource ());//橫向專案資料來源
		  	map.put("subReportHorizontalRPdir",this.getRealRealPath("horizontalProjects.jasper"));//橫向專案jasper路徑
	        noSource s1=new noSource();//注意這裡nosource沒有任何資料,是主報表的資料來源,由於在主報表當中只含有子報表,所以資料來源為空
	       
		JasperPrint jasperPrint = null;
		try {
			JasperReport jasperReport = (JasperReport) JRLoader
					.loadObject(jasperFile.getPath());//將檔案轉化為jasperReport型別
			jasperPrint = JasperFillManager.fillReport(jasperReport,
					map, s1);//填充檔案 引數 資料來源
		
		} catch (JRException e) {
			e.printStackTrace();
		}
		if (null != jasperPrint) {
			FileBufferedOutputStream fbos = new FileBufferedOutputStream();
			JRPdfExporter exporter = new JRPdfExporter();
			exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, fbos);//內部實現應該是用的反射
			//將內容輸出到fbos流中
			exporter
					.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
			
			try {
				exporter.exportReport();//匯出對應的檔案
				fbos.close();
				if (fbos.size() > 0) {
					//設定檔案格式
					response.setContentType("application/pdf");
					response.setContentLength(fbos.size());
					ServletOutputStream ouputStream = response
							.getOutputStream();
					try {
						fbos.writeData(ouputStream);//將資料寫入網路流當中
						fbos.dispose();
						ouputStream.flush();
					} finally {
						if (null != ouputStream) {
							ouputStream.close();
						}
					}
				}
			} catch (JRException e1) {
				e1.printStackTrace();
			} finally {
				if (null != fbos) {
					fbos.close();
					fbos.dispose();
				}
			}
		}
	}
}
資料來源設計: UniversityAcademyDataSource 
package com.jasperReport.dataSource;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;

public class UniversityAcademyDataSource implements JRDataSource {//實現此介面 jasperReport通過呼叫此介面來呼叫我們的資料來源
	private List dataLst=this.getMapList();
	private int index = -1;
	@Override
	public Object getFieldValue(JRField field) throws JRException {
		Object value = null;
		String fieldName = field.getName();
		Map map=(Map)this.dataLst.get(index);//dataLst中含有從資料庫中取出的真實資料
		if ("BMMC".equals(fieldName)) {//BMMC對應報表的fieldName
			value = map.get("BMMC");
		} else if ("paperNum".equals(fieldName)) {
			value = Integer.parseInt((String)map.get("paperNum"));
		} else if ("writeNum".equals(fieldName)) {
			value = Integer.parseInt((String)map.get("writeNum"));
		} else if ("EIMagazineNum".equals(fieldName)) {
			value = Integer.parseInt((String)map.get("EIMagazineNum"));
		}else if ("EIMeetingNum".equals(fieldName)) {
			value = Integer.parseInt((String)map.get("EIMeetingNum"));
		}else if ("ISTPNum".equals(fieldName)) {
			value = Integer.parseInt((String)map.get("ISTPNum"));
		}else if ("SCINum".equals(fieldName)) {
			value = Integer.parseInt((String)map.get("SCINum"));
		}else if ("CSSCI".equals(fieldName)) {
			value = Integer.parseInt((String)map.get("CSSCI"));
		}
		return value;
	}

	@Override
	public boolean next() throws JRException {
		// TODO Auto-generated method stub
		index++;
		return index < this.dataLst.size();
	}

	public List getMapList()
	{
		List lst=new ArrayList();
	    
	    for(int i=0;i<11;i++)
	    {
	    	Map map=new HashMap();
	    	map.put("BMMC", "學院"+i);
	    	map.put("paperNum", ""+i);
	    	map.put("writeNum", ""+i);
	    	map.put("EIMagazineNum",""+i);
	    	map.put("EIMeetingNum", ""+i);
	    	map.put("ISTPNum", ""+i);
	    	map.put("SCINum", ""+i);
	    	map.put("CSSCI", ""+i);
	    	lst.add(map);
	    }
	    return lst;
	}
}
資料來源設計:noSource
package com.jasperReport.dataSource;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;

import com.mengya.servlet.financeInfo;

public class noSource implements JRDataSource {//主報表中不含任何資料

	private int index = -1;
	@Override
	public Object getFieldValue(JRField field) throws JRException {
		return null;
	}

	@Override
	public boolean next() throws JRException {
		index++;
		return index<1;//如果index<2會導致出現一個空白頁面 index<3會出現兩個 依此類推
	}

}

五 遇到的問題

  1)中文不顯示

首先,在用iReport設計報表時將要顯示中文資料的地方的屬性設定如下:    Font name: 宋體 (中文字型)   

 PDF font name:   STSong-Light

   PDF Encoding:  UniGB-UCS2-H(ChineseSiplified)   

 PDF  Embeded:

2)linux記憶體溢位

  在catlina.sh中加入

JAVA_OPTS="-Xms128m -Xmx1024m -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC“

具體原因見部落格

3)如果報表中含有多個表格,則需要在主報表中建立子報表。如下圖所示:

每個子報表需要放到不同的detail中,否則會出現子報表重疊在一起的情況。子報表的資料來源在主報表中以引數的形式傳入。

  

六 建議

    在設計報表時,想要提高開發速度,沒有必要每個都從頭設計(比如想要顯示中文label,必須設定若干屬性才可以),可以直接從我的專案裡面copy,也可以設計好一項後在design頁面中直接複製。