最近遇到了一个打印的业务要求,根据客户选择多个月份得日期来获得该日期下产生的交易明细的打印,其中每个月份要求单独打印。此时就很尴尬了,因为一般我们做都是引入一个数据源,来制作一个报表,=,现要求多个数据源生成多张报表,这该如何是好?
现有两种解决方案:
第一种:
因为可以拿到每个月的数据,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 paramObj = new ArrayList();//ireport的参数$P{}
private Map returnMap = new HashMap();//返回前端的结果map
//private String[] pdfNameAry;
private List jsperList = new ArrayList();//所需要的模板jasper 集合
/**
* A4纸打印:此处没更新业务状态,因为接口走的是明细查询的,此处只做模板用
*/
public String creditPrint(){
logger.info("进入到信用卡回单打印服务层,打印A4纸");
long startTime = System.currentTimeMillis();
HttpServletRequest request = ServletActionContext.getRequest();
OutputStream output = null;
Map paramterMap = new HashMap();//参数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 mmpMap = josnObj;
Set 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 onceMonthDate = (List) mmpMap.get(key);//拿到每个月不为空的数据源 泛型可以为任何,,它不做校验
//修改每个对象的值
for (int j = 0; j < onceMonthDate.size(); j++) {
ICommUtil.setObjValueByMap(
(Map) 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;
}*/