如何在导出中组合多个jasper报告时重新计算页码?

我已经决定在收到聊天中的两个问题后通过此问答,并在“组合”jasper报告中回答有关如何处理页码的答案

在java中组合报表时使用

JasperPrint jasperPrint1 = JasperFillManager.fillReport(report1, paramMap); JasperPrint jasperPrint2 = JasperFillManager.fillReport(report2, paramMap); List jasperPrintList = Arrays.asList(jasperPrint1, jasperPrint2); JRPdfExporter exporter = new JRPdfExporter(); exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList)); 

页码和总页码

          

总是重新启动我列在列表中的每个报告,有没有办法可以重新计算这些?

考虑到我的最终合并报告,我想在每个页面上显示当前页面(以及正确的总页数)。

jasper-report方式是不在java中组合报告,而是使用主报告,并将不同的报告作为子报告包含在此主报告中,将页码移动到主报告中。

但是,如果我们喜欢在java中结合问题,我们也可以使用java来编辑和更正页码。

这个想法是在报告中设置“标记”,然后对JasperPrint进行后处理,用实际页码替换标记。

jrxml (使用freemaker样式没有羞耻)

          

java的

定义我的标记

 private static final String CURRENT_PAGE_NUMBER = "${CURRENT_PAGE_NUMBER}"; private static final String TOTAL_PAGE_NUMBER = "${TOTAL_PAGE_NUMBER}"; 

在我的报告的fillReport之后用真实数字替换我的所有标记

 //First loop on all reports to get totale page number int totPageNumber=0; for (JasperPrint jp : jasperPrintList) { totPageNumber += jp.getPages().size(); } //Second loop all reports to replace our markers with current and total number int currentPage = 1; for (JasperPrint jp : jasperPrintList) { List pages = jp.getPages(); //Loop all pages of report for (JRPrintPage jpp : pages) { List elements = jpp.getElements(); //Loop all elements on page for (JRPrintElement jpe : elements) { //Check if text element if (jpe instanceof JRPrintText){ JRPrintText jpt = (JRPrintText) jpe; //Check if current page marker if (CURRENT_PAGE_NUMBER.equals(jpt.getValue())){ jpt.setText("Page " + currentPage + " of"); //Replace marker continue; } //Check if totale page marker if (TOTAL_PAGE_NUMBER.equals(jpt.getValue())){ jpt.setText(" " + totPageNumber); //Replace marker } } } currentPage++; } } 

注意:如果是我的一个项目中的代码,我不会嵌入这个数量的for和if语句,而是将代码提取到不同的方法,但为了清楚起见,我决定将它作为一个代码块发布

现在它准备出口了

 JRPdfExporter exporter = new JRPdfExporter(); exporter.setExporterInput(SimpleExporterInput.getInstance(jasperPrintList)); .... 

这是正确的,但如果有JRPrintFrame,如果你的评论是在这个代码中找不到它。 下面是为我工作的那个:(你应该找出TOTAL_PAGE_NUMBER在哪个容器元素中!

 private void correctPageNumbers(List jasperPrintList) { // First loop on all reports to get totale page number int totPageNumber = 0; for (JasperPrint jp : jasperPrintList) { totPageNumber += jp.getPages().size(); } // Second loop all reports to replace our markers with current and total // number int currentPage = 1; for (JasperPrint jp : jasperPrintList) { List pages = jp.getPages(); // Loop all pages of report for (JRPrintPage jpp : pages) { List elements = jpp.getElements(); // Loop all elements on page for (JRPrintElement jpe : elements) { if (jpe instanceof JRSubreport) { JRSubreport jrr = (JRSubreport) jpe; jrr.getBackcolor(); } // Check if text element if (jpe instanceof JRPrintText) { JRPrintText jpt = (JRPrintText) jpe; System.out.println("jpt.value: " + jpt.getValue() + " | " + "jpt.text" + jpt.getText()); // Check if totale page marker if (TOTAL_PAGE_NUMBER.equals(jpt.getValue())) { jpt.setText(" " + totPageNumber); // Replace marker } } else if (jpe instanceof JRTemplatePrintFrame) { List frameElements = ((JRTemplatePrintFrame) jpe).getElements(); for (JRPrintElement jpef : frameElements) { if (jpef instanceof JRPrintText) { JRPrintText jpt = (JRPrintText) jpef; System.out.println("jpt.value: " + jpt.getValue() + " | " + "jpt.text" + jpt.getText()); // Check if totale page marker if (TOTAL_PAGE_NUMBER.equals(jpt.getValue())) { jpt.setText(" " + totPageNumber); // Replace // marker } } } } } currentPage++; } } 

}

还有另一个简单的解决方案,它不会涉及JasperPrint和JasperPages等所有jasper类。 方法是获取先前打印件中的页数并将其添加到下一个打印件的PAGE_NUMBER变量中。

假设我们有三个碧玉印花。 jasperPrint1,jasperPrint2,jasperPrint3,因为jasperPrint1有动态内容和变量号。 页面很难知道下一次打印的页码。 解决方案是 –

将第一个打印输出到临时pdf文件 –

 JasperExportManager.exportReportToPdfFile(jasperPrint1, tempPdfFile.getAbsolutePath()); 

初始化一个变量,该变量用0跟踪所有先前打印的页面;

 pafeSofar = 0 

写一个返回no的方法。 pdf文件中的页面:

 private int numberOfPages(String filePath) throws IOException { PdfReader pdfReader = new PdfReader(filePath); return pdfReader.getNumberOfPages(); } 

这里PdfReader是iText的一个类。 您可以添加maven依赖项或手动下载.jar并将其添加到类路径中。

对于itext pdf阅读器的Maven依赖关系如下:

  com.itextpdf itextpdf 5.5.0  

使用这种方法得不到。 以前的报告中的页面。

 pagesSofar = pagesSofar + numberOfPages(tempPdfFile.getAbsolutePath());` 

创建一个参数以将此变量传递到其中并将该参数添加到其他报表中的PAGE_NUMBER。

 parameterMap.put("previousPageNumber", pagesSofar);` 

在.jrxml文件中:

     ` 

这里parameterMap是你在每个报告中传递的参数的地图 –

 JasperPrint jasperPrint2 = JasperFillManager.fillReport(jasperReport3, parameterMap, new JREmptyDataSource()); 

我受到@Adityaz7答案的启发,我认为他的方法是最好的。 但我已经完成了这项工作,无需为项目添加库并创建临时PDF文件。

首先修改模板并添加一个参数来保存先前页面的数量:

  

在包含页码的report元素中插入以下表达式:

  

您必须使用String.valueOf()方法,因为如果您使用元素$V{PAGE_NUMBER} + $P{PREVIOUS_PAGE_NUMBER}的简单总和,Jasper将把它作为字符串的总和处理,并将这两个数字打印为连接。 (例如将打印11而不是2)

在您的java代码中,创建一个变量来保存先前页面的数量,并将其作为参数传递给Jasper。 然后填写第一个报告,只需将包含报告页面的列表大小添加到prevPageNumber ,并将其作为参数传递给第二个报告,依此类推:

 int prevPageNumber = 0; HashMap paramMap = new HashMap(); paramMap.put("PREVIOUS_PAGE_NUMBER", prevPageNumber); // fill the first report with prevPageNumber = 0 JasperPrint jasperPrint1 = JasperFillManager.fillReport(report1, paramMap); if(jasperPrint1 != null && jasperPrint1.getPages() != null) { // add previous report page number prevPageNumber += jasperPrint1.getPages().size(); } paramMap.put("PREVIOUS_PAGE_NUMBER", prevPageNumber); JasperPrint jasperPrint2 = JasperFillManager.fillReport(report2, paramMap); 

我写这个内联是为了尊重问题中使用的结构OP,但是如果你有超过2个报告要打印,当然最好这样做。