1. 程式人生 > >Ireport多個報表整合成一張pdf

Ireport多個報表整合成一張pdf

最近遇到了一個列印的業務要求,根據客戶選擇多個月份得日期來獲得該日期下產生的交易明細的列印,其中每個月份要求單獨列印。此時就很尷尬了,因為一般我們做都是引入一個數據源,來製作一個報表,=,現要求多個數據源生成多張報表,這該如何是好?

現有兩種解決方案:

第一種:

因為可以拿到每個月的資料,for迴圈同步請求生成多份pdf,每個月佔一份。存於伺服器下,然後再將後臺拼接起來,此方法明顯不足,工作量很大,多次請求後臺。

第二種:

只請求一次後臺,將後臺的總的json資料資料傳到後臺,然後將每個月的資料和查詢引數分別生成對應的jasper,然後將每個jasper放到集合裡,最後將集合作為引數生成報表,具體實現看程式碼。

前端程式碼
/**
 * 上送賬戶交易明細查詢介面
 * @param startDate 查詢日期(信用卡只能一個月一個月的查)
 */
function sendQueryDetails_Bimpl(queryTime){
		try {
			parent.writeTradeLog("[信用卡賬單明細查詢]進入上送介面方法!");
			//組裝上送資料
			var requestCode = "creditTradeDetailQuery";
			var baseDto = parent.getBaseDtoDataCom();//業務流水號,裝置號,裝置機構號,裝置機構號,請求流水號
			var machNo = baseDto.deviceNo;
			var busiID = baseDto.acceptId;
			var async = true;
			var head= null;
			var requestData = {};
			parent.concatSendObjByObj(requestData,baseDto,"baseDto");
			requestData["queryCreditTradeDetailsReqDto.source"] = "CT"; //交易來源
			requestData["queryCreditTradeDetailsReqDto.cardno"] = important.creditNo; //信用卡卡號
			requestData["queryCreditTradeDetailsReqDto.acctym"] = queryTime;//賬單年月 如201801-201807
			requestData["queryCreditTradeDetailsReqDto.crcytp"] = "A"; //本外幣選擇
			requestData["queryCreditTradeDetailsReqDto.pagetp"] = "";  //翻頁標識  	首次查詢上送空,下翻頁查詢上送1
			requestData["queryCreditTradeDetailsReqDto.iactdt"] = "";  //入賬日期 	 翻頁查詢時上送上頁返回的最後一條記錄入帳日期
			requestData["queryCreditTradeDetailsReqDto.rpaydt"] = "";  //記錄日期 	 翻頁查詢時上送上頁返回的最後一條記錄記錄日期
			requestData["queryCreditTradeDetailsReqDto.rpaytm"] = "";  //消費時間 	 翻頁查詢時上送上頁返回的最後一條記錄消費時間
			requestData["queryCreditTradeDetailsReqDto.tranno"] = "";  //交易流水號	 翻頁查詢時上送上頁返回的最後一條記錄交易流水號
			requestData["queryCreditTradeDetailsReqDto.ickpin"] = "0"; //是否檢查密碼   不檢查密碼 
			requestData["queryCreditTradeDetailsReqDto.qrypwd"] = "";  //密碼
			requestData["queryCreditTradeDetailsReqDto.qryctp"] = "0"; //查詢條件  0:返回帳戶交易明細,預設方式;1:按查詢卡號返回交易明細
			pLoading("正在查詢,請稍候。。");
				$.request_busi(requestCode,machNo,busiID,requestData,async,function(data){
					parent.writeTradeLog("[" + busiID  + "]信用卡賬戶交易明細資訊查詢結束,結果為[" + data.returnMap.errMsg + "]...");
					pLoadend();
					if(validZero(data.returnMap.errCode)){
						var mapObj = data.returnMap.mapList;//map物件{1805:null,1806:[20],......}返回資料物件
						//分別拿到每個月的資料,生成單個月的pdf,再到後臺拼接pdf
						var monthAry = [];//key值陣列1801  1802
						var totalData = [];//用來裝在n個月的資料{,,,,,,}
						for(var prop in mapObj){//遍歷map拿到單個數組,在遍歷陣列,放到一個大的陣列中
							if(mapObj.hasOwnProperty(prop)){
								monthAry.push(prop);
								if(mapObj[prop] != null){//無賬單情況下此資料為null
									if(!mapObj[prop].length == 0){
										for ( var i = 0; i < mapObj[prop].length; i++) {
											totalData.push(mapObj[prop][i]);//把陣列每個元素新增到總資料中,用於展示
										}
									}
								}
								}
							}
						detailquery_details = totalData;
						if(detailquery_details){
							detailquery_pageindex = 1;//起始頁碼
							detailquery_pagesize = Math.ceil(detailquery_details.length/7);//向上取整  >=該引數  每頁顯示數量
						}
						//顯示交易明細
						showQueryDetails_V();
						var flag = false;//生成pdf是否成功
						//前端展示完交易明細後,後端做生成pdf  只要有一個月份的資料不為空即可
						for ( var i = 0; i < monthAry.length; i++) {
							if(mapObj[monthAry[i]] != null){
								flag = true;
								break;
							}
						}
						if(flag){
							//後臺irport需要用到的引數:
							var parmter = {"acctNo":parent.itm_newAccNo(important.creditNo),"acctName":parent.itm_replaceName(important.custName)};
							var parmterStr = JSON.stringify(parmter);
							var mapStr = JSON.stringify(mapObj);
							pLoading("正在生成pdf,請稍候。。");
							$.ajax({
								url:"/vts/creditPrintAction!creditPrint.action",
								type:"post",
								data:{"sendDate":mapStr,"parmterStr":parmterStr},
								timeout:12000,
								async:true,
								daType:"json",
								success:function(data){
									pLoadend();
									if(data.returnMap.errCode == "0000"){
										//填充iframe內容
										$("#credit_printIframe").attr("src","../../../booktemp/pdf/credit/" +data.returnMap.pdfName);//因為你的絕對路徑是在此頁面下必須跳到booktemp目錄下
										pdfPageNum = data.returnMap.pageNum;
										var isOkFlag = parent.pToolLib.CreateDir("D://Receipt");// 返回值:0成功 1失敗
										if(isOkFlag == "0"){
											parent.writeTradeLog("個人回單列印建立資料夾成功");
											parent.pToolLib.DecodeBase64(data.returnMap.base64Data, "D://Receipt//creditA4.pdf");
											parent.writeTradeLog("個人回單列印生成成功!");
										}else{
											parent.writeTradeLog("個人回單列印建立資料夾失敗!");
											$("#print").errorReminder("個人回單列印建立資料夾失敗!", 3000); 
										}
									}else{
										parent.writeTradeLog(data.returnMap.errMsg);
										$("#print").errorReminder(data.returnMap.errMsg, 3000);
										return;
									}
								},
								error:function(request,status,errorthrow){
									pLoadend();
									$("#print").errorReminder(status, 3000);
									return;
								}
							});
						}else{
							$("#queryDetail").errorReminder("查詢無記錄!", 3000);
							return;
						}
					}else{
						//需要賦預設值
						pWarn(data.returnMap.errMsg.replace( /[0-9]*/g,''),function(){
						return;
						});
					}
				},head);
		} catch (e) {
			parent.writeTradeLog("上送信用卡賬單明細查詢出現異常:"+e.message);
			parent.errPageAndWriteLogCom(this,"上送信用卡賬單明細查詢出現異常",e.message);
		}
}



後端程式碼
@Controller("CreditPdfService")
@Scope("prototype")
public class CreditPdfService extends ActionSupport{
	
	private static final long serialVersionUID = 1L;
	private static Logger logger = Logger.getLogger(CreditPdfService.class);
	
	private List<PersonalBillsParmter> paramObj = new ArrayList<PersonalBillsParmter>();//ireport的引數$P{}
	private Map<String,String> returnMap = new HashMap<String, String>();//返回前端的結果map
	//private String[] pdfNameAry;
	private List<JasperPrint> jsperList = new ArrayList<JasperPrint>();//所需要的模板jasper 集合
	
	/**
	 * A4紙列印:此處沒更新業務狀態,因為介面走的是明細查詢的,此處只做模板用
	 */
	public String creditPrint(){
		logger.info("進入到信用卡回單列印服務層,列印A4紙");
		long startTime = System.currentTimeMillis();
		HttpServletRequest request = ServletActionContext.getRequest();
		OutputStream output = null;
		Map<String,Object> paramterMap = new HashMap<String, Object>();//引數map
		//把json字串轉為物件
		String parmterStr = request.getParameter("parmterStr");
		PersonalBillsParmter parmter = JSON.parseObject(parmterStr,PersonalBillsParmter.class);
		paramterMap.put("acctName", parmter.getAcctName());
		paramterMap.put("acctNo", parmter.getAcctNo());
		String logoPath = request.getSession().getServletContext().getRealPath("/trade/print/personalbillsprint/jasper/logo.png");
		paramterMap.put("logo", logoPath);
		ByteArrayOutputStream  byteOut = new ByteArrayOutputStream();
		String jsonStr = request.getParameter("sendDate");//{"1806":null,"1807":null,"1808":[{"":"",......}],.....}
		try {
			File file = new File(request.getSession().getServletContext().getRealPath("/trade/print/creditbillsprint/jasper/credit.jasper"));//jasper檔案路徑   trade/sss
			// net.sf.json.JSONObject 包關聯其它包,少包,故用alibb
			JSONObject josnObj = JSONObject.parseObject(jsonStr);//就是一個map物件    hashTable的value 不能為null
			Map<String, Object> mmpMap = josnObj;
			Set<String> set = mmpMap.keySet();//set 迭代或者加強for迴圈
			for (String key :set) {
				if(mmpMap.get(key) !=null){
					logger.info("信用卡查詢時間為:" + key);
					parmter.setQueryTime(key);
					paramterMap.put("queryTime", "20" + key);//儲存日期查詢引數
					QueryCreditTradeDetailsResDto resDto = new QueryCreditTradeDetailsResDto();
					List<QueryCreditTradeDetailsResDto> onceMonthDate = (List<QueryCreditTradeDetailsResDto>) mmpMap.get(key);//拿到每個月不為空的資料來源   泛型可以為任何,,它不做校驗
					//修改每個物件的值
					for (int j = 0; j < onceMonthDate.size(); j++) {
						ICommUtil.setObjValueByMap(
								(Map<String, Object>) onceMonthDate.get(j), resDto);// 將每個map物件轉為實體類
						// 修改介面返回欄位 交易金額 +10,-20
						if (!StringUtils.isBlank(resDto.getTranam())) {
							resDto.setTranam(resDto.getTramfg()
									+ resDto.getTranam());
						}
						// 修改 介面返回的欄位卡末尾四位
						if (!StringUtils.isBlank(resDto.getCrdnof())) {
							resDto.setCrdnof("****" + resDto.getCrdnof());
						}
					}
					 JRDataSource dataSource = new JRBeanCollectionDataSource(onceMonthDate);//資料來源
					 JasperReport jasper = (JasperReport) JRLoader.loadObject(file);//構造jasper檔案 此處使用同一個jasper模板,如果你有其它的模板也可以拼湊
					 JasperPrint jasperPrint = JasperFillManager.fillReport(jasper,paramterMap,dataSource);//用資料填充jasperreport檔案
					 jsperList.add(jasperPrint);
				}
			}
			//響應給客戶端的檔案型別和報文標頭檔案名
			String uniqueId = UUIDHelper.getUUIDString(false, false);//保證每個月產生的檔名唯一
			String acctno = parmter.getAcctNo();
			String acctnoAfterFourth = acctno.substring(acctno.length()-4,acctno.length());//擷取後四位
			String pdfName =acctnoAfterFourth + "-" + parmter.getQueryTime() + "-" + uniqueId+ ".pdf";
			JRPdfExporter exporter = new JRPdfExporter();
			exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, jsperList);//設定匯出哪個模板
			exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, byteOut);//設定匯出流模板(把模板轉換成位元組流)  這裡用記憶體位元組流,儲存在記憶體中,若用其他如oututstream,瀏覽器器預設下載
			exporter.exportReport();//匯出檔案
			String filePath = request.getSession().getServletContext().getRealPath("/booktemp/pdf/credit");//建立資料夾(用於存放pdf)
			File pdfFile = new File(filePath);
			if(!pdfFile.exists()){
				pdfFile.mkdirs();
			}
			File newFle = new File(filePath +File.separator + pdfName);
			output = new FileOutputStream(newFle);
			output.write(byteOut.toByteArray());//將記憶體位元組流寫入到該檔案中去
			output.close();
			byteOut.close();
			if(newFle.length() > 0){
				long distanceTime = System.currentTimeMillis() - startTime;
				logger.info(parmter.getQueryTime() + "月份信用卡賬單明細pdf下載到伺服器成功!,檔案大小為" + newFle.length()/1024 + "kb" + "此次耗時為" + distanceTime +"毫秒,pdf檔名為:" + pdfName);
				String base64Data = Base64Helper.fileToBase64(filePath +File.separator + pdfName, new StringBuffer());
				if(!"".equals(base64Data) || null != base64Data){
					returnMap.put("errCode", "0000");
					returnMap.put("base64Data", base64Data);//把base64字串傳遞給前端
					returnMap.put("pdfName", pdfName);
					//獲取pdf生成的頁數
					PdfReader read = null;
					int pageNum = 0;
					try {
						read = new PdfReader(filePath +File.separator + pdfName);
						pageNum = read.getNumberOfPages();
						logger.info("pdf的頁碼數為" + pageNum + "pdf檔名為 " + pdfName);
					} catch (IOException e) {
						e.printStackTrace();
						returnMap.put("errCode", "0002");
						returnMap.put("errMsg", "獲取頁碼失敗,失敗原因為!" + e.getMessage());
					}
					returnMap.put("pageNum", Integer.toString(pageNum));
				}else{
					logger.info("信用卡賬單明細pdf轉base64字串失敗!");
					returnMap.put("errCode", "0003");
					returnMap.put("errMsg", "信用卡賬單明細pdf轉base64字串失敗!");
				}
			}else{
				logger.info("信用卡賬單明細pdf下載到伺服器失敗!");
				returnMap.put("errCode", "0002");
				returnMap.put("errMsg", "信用卡賬單明細pdf下載到伺服器失敗!");
			}
			
		} catch (Exception e) {
			returnMap.put("errCode", "9999");
			returnMap.put("errMsg", "列印異常!");
			e.printStackTrace();
			logger.error("信用卡賬單明細列印異常,異常資訊為" + e.getMessage());
		}finally{
			if(null != output){
				try {
					output.close();
				} catch (IOException e) {
					logger.warn("信用卡賬單明細關閉輸出流異常,"+ e.getMessage(),e);
				}
			}
			if(null != byteOut){
				try {
					byteOut.close();
				} catch (IOException e) {
					logger.warn("信用卡賬單明細關閉輸出位元組記憶體流異常,"+ e.getMessage(),e);
				}
			}
		}
		return SUCCESS;
	}

這裡是pdf拼接的,因為沒用到就註釋了
	/**
	 * 目的:拼接伺服器上的pdf 1.你要拼接pdf檔案地址陣列  2.拼接後新的檔案的地址
	 * 注意點:1 因為你要拼接pdf,就要到伺服器去拿資料,所以每個客戶生成的pdf都不能刪除。
	 * 		2為保證你要拼接的pdf必須唯一,所以必須保證每個客戶產生每個月的pdf檔名必須唯一。
	 * 		3將拼接好了的新的pdf和其單個pdf刪除
	 */
/*	public String combineOrDletePdf(){
		HttpServletRequest request = ServletActionContext.getRequest();
		File filePath = new File(request.getSession().getServletContext().getRealPath("/booktemp/pdf") +File.separator + "credit");//pdf資料夾路徑
		String[] pdfPath = pdfNameAry;//用來裝載每個月pdf的路徑 0091-1806-f45a0e4d6db5406686e2f0f23606d7f2.pdf
		String newFile = filePath + File.separator + UUIDHelper.getUUIDString(false, false) + "-combine.pdf";//防止其它客戶也命相同名字,出現讀寫問題
		for (int i = 0; i < pdfPath.length; i++) {
			pdfPath[i] = filePath + File.separator + pdfPath[i];//[booktemp\pdf\credit\0091-1807-f44953347c4d4056b68e3ca2c0fb123c.pdf,....]
		}
		if(pdfNameAry.length > 1){
			Document document = null;
			try {
				Rectangle re = new PdfReader(pdfPath[0]).getPageSize(1);
				document = new Document(re);
				PdfCopy copy = new PdfCopy(document,new FileOutputStream(newFile));
				document.open();
				for (int i = 0; i < pdfPath.length; i++) {
					PdfReader reader = new PdfReader(pdfPath[i]);//每個pdf檔案
					int n = reader.getNumberOfPages();//當前pdf的頁碼
					for (int j = 1; j <=n; j++) {
						document.newPage();
						PdfImportedPage page = copy.getImportedPage(reader, j);
						copy.addPage(page);//把當前pdf的當前頁新增到新的pdf中
					}
				}
			} catch (Exception e) {
				returnMap.put("errCode", "9999");
				returnMap.put("errMsg", "拼接失敗,"+e.getMessage());
				logger.error("拼接pdf異常,異常資訊為" + e.getMessage());
				e.printStackTrace();
			}finally{
				document.close();
				//說明拼接成功
				logger.info("拼接pdf成功!");
				returnMap.put("errCode", "0000");
				String pdfName =  newFile.substring(newFile.lastIndexOf("\\") + 1);//pdf檔名
				returnMap.put("pdfName",pdfName);
				String base64Data = Base64Helper.fileToBase64(filePath +File.separator + pdfName, new StringBuffer());
				if(!"".equals(base64Data) || null != base64Data){
					returnMap.put("errCode", "0000");
					returnMap.put("base64Data", base64Data);//把base64字串傳遞給前端
					returnMap.put("pdfName", pdfName);
					//獲取pdf生成的頁數
					PdfReader read = null;
					int pageNum = 0;
					try {
						read = new PdfReader(filePath +File.separator + pdfName);
						pageNum = read.getNumberOfPages();
						logger.info("信用卡拼接pdf的頁碼數為" + pageNum + "拼接pdf檔名為 " + pdfName);
					} catch (IOException e) {
						e.printStackTrace();
						returnMap.put("errCode", "0002");
						returnMap.put("errMsg", "獲取頁碼失敗,失敗原因為!" + e.getMessage());
					}
					returnMap.put("pageNum", Integer.toString(pageNum));
				}else{
					logger.info("信用卡賬單明細pdf轉base64字串失敗!");
					returnMap.put("errCode", "0003");
					returnMap.put("errMsg", "信用卡賬單明細pdf轉base64字串失敗!");
				}
				//刪除單個與合併的pdf
				for (int i = 0; i < pdfPath.length; i++) {
					logger.info("[[combineOrDletePdf]單個月份的檔案地址為:" + pdfPath[i]);
					logger.info("[[combineOrDletePdf]刪除單個月份pdf是否成功:" + new File(pdfPath[i]).delete());
				}
			}
		}else{
			String pdfName = pdfPath[0].substring(pdfPath[0].lastIndexOf("\\") + 1);
			returnMap.put("errCode", "0000");
			returnMap.put("pdfName", pdfName);//取得檔名
			//獲取pdf生成的頁數
			PdfReader read = null;
			int pageNum = 0;
			try {
				read = new PdfReader(filePath +File.separator + pdfName);
				pageNum = read.getNumberOfPages();//當前pdf的頁碼
			} catch (IOException e) {
				e.printStackTrace();
				returnMap.put("errCode", "0002");
				returnMap.put("errMsg", "獲取頁碼失敗,失敗原因為!" + e.getMessage());
			}
			returnMap.put("pageNum", Integer.toString(pageNum));
		}
		return SUCCESS;
	}*/