I have created two report jrxml with jasper report. In my java program I merge the two report into one PDF with iText.
The problem is that the pdf contains only one report plus a blank page.
I have also done this proof:
in my java program creation report one creation report two, merge and I see pdf containig only report one plus blank page
in my java program creation report two and then creation report one, merge and I see pdf containing only report two plus blank page
I have to obtain the pdf with both reports
Does someone help me to solve the problem?
Thanks in advance
Attach the code of my java program:
#Name("pdfFactory")
public class PdfScalareFactory {
private static final String JASPER_FILE_MOVIMENTI = "scalarePdf/pdf_movimenti.jrxml";
private static final String JASPER_FILE_SCALARE = "scalarePdf/pdf_scalare.jrxml";
#SuppressWarnings("rawtypes")
public byte[] rawPdf(BeScalare beScalare, String codTabulato, String output) throws JRException, IOException {
JRBeanArrayDataSource dataSource = new JRBeanArrayDataSource(new Object[]{beScalare});
//report's list
List<byte[]> pdfFilesAsByteArray = new ArrayList<byte[]>();
//Report one
Class cScalare = this.getClass();
ClassLoader clScalare = cScalare.getClassLoader();
InputStream isScalare = clScalare.getResourceAsStream(JASPER_FILE_SCALARE);
JasperDesign jasDesignScalare = JRXmlLoader.load(isScalare);
//compile report one
JasperReport reportScalare = JasperCompileManager.compileReport(jasDesignScalare);
//parameters report one
Map<String, Object> paramScalare = new HashMap<String, Object>();
JRBeanCollectionDataSource itemsScalareSaldiPerValuta = new JRBeanCollectionDataSource(beScalare.getLstBeScalareSaldiPerValuta());
paramScalare.put("scalareSaldiPerValuta", itemsScalareSaldiPerValuta);
//fill report one
JasperPrint jasperPrintScalare = JasperFillManager.fillReport(reportScalare, paramScalare, dataSource);
pdfFilesAsByteArray.add(JasperExportManager.exportReportToPdf(jasperPrintScalare));
//Report two
Class c = this.getClass();
ClassLoader cl = c.getClassLoader();
InputStream is = cl.getResourceAsStream(JASPER_FILE_MOVIMENTI);
JasperDesign jasDesign = JRXmlLoader.load(is);
//compile report two
JasperReport reportMovimenti = JasperCompileManager.compileReport(jasDesign);
//parameters report two
Map<String, Object> paramMovimenti = new HashMap<String, Object>();
BufferedImage imgNumeroVerde = ImageIO.read(getClass().getResource("/scalarePdf/headphones.png"));
paramMovimenti.put("numeroVerde", imgNumeroVerde);
BufferedImage imgInternet = ImageIO.read(getClass().getResource("/scalarePdf/internet.png"));
paramMovimenti.put("internet", imgInternet);
JRBeanCollectionDataSource itemsScalareMovimenti = new JRBeanCollectionDataSource(beScalare.getLstBeScalareMovimenti());
paramMovimenti.put("scalareMovimenti", itemsScalareMovimenti);
//fill report two
JasperPrint jasperPrintMovimenti = JasperFillManager.fillReport(reportMovimenti, paramMovimenti, dataSource);
pdfFilesAsByteArray.add(JasperExportManager.exportReportToPdf(jasperPrintMovimenti));
//merge the two reports in one
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Document document = null;
PdfCopy writer = null;
for (byte[] pdfByteArray : pdfFilesAsByteArray) {
try {
PdfReader reader = new PdfReader(pdfByteArray);
int numberOfPages = reader.getNumberOfPages();
if (document == null) {
document = new Document(reader.getPageSizeWithRotation(1));
writer = new PdfCopy(document, outStream); // new
document.open();
}
PdfImportedPage page;
for (int i = 0; i < numberOfPages;) {
++i;
page = writer.getImportedPage(reader, i);
writer.addPage(page);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
document.close();
outStream.close();
return outStream.toByteArray();
}
}
Problem is in the data source and not in merging. You create one data source for both reports but the first report will consume it and then the second report has data source with pointer at the end.
You use JRBeanArrayDataSource which implements JRRewindableDataSource so you can call the moveFirst() method to return data source pointer on the first position:
//Report two
dataSource.moveFirst();
Or you can create the data source again for the second report:
//Report two
dataSource = new JRBeanArrayDataSource(new Object[]{beScalare});
Note: But as Amongalen mentioned in the comment it is easier to merge two and more Jasper reports using JRPdfExporter and List<JasperPrint> instance as an input.
Related
I have a problem, i generate XLSX with JasperReports, but if i want print document, he's break page not correctly.
I need last page footer not split.
I can't use ignorePagination or ignoreMargins, because they delete space (delete page break) and my last page footer split on another page...
Split type on last page footer set Prevent
What do you recommend to me?
JasperReports library - 6.3.0
iReport - 5.6.0
Java - 1.8
MS Excel - 2016
My report design:
The generated XLSX file looks like:
You can see, if page break move on 1 cell down, page print correctly, but i can't open every document for correction him
The splitType for lastPageFooter is set as Prevent.
Java code
public void createReport(Map<String,Object> dataMap, HttpServletResponse response, HttpServletRequest request){
String pathToServletRoot = request.getSession(true).getServletContext().getRealPath("/");
String sourceFileName = pathToServletRoot + "/resources/template/jasper/reportT12.jasper";
try {
ArrayList<DataBean> dataList = dataBeanArrayList(dataMap);
JRBeanCollectionDataSource beanColDataSource = new JRBeanCollectionDataSource(dataList);
Map parameters = new HashMap();
try {
JasperPrint jasperPrint = JasperFillManager.fillReport(sourceFileName,
parameters, beanColDataSource);
JRXlsxExporter exporter = new JRXlsxExporter();
ByteArrayOutputStream xlsxReport = new ByteArrayOutputStream();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(xlsxReport));
SimpleXlsxReportConfiguration configuration = new SimpleXlsxReportConfiguration();
configuration.setOnePagePerSheet(false);
configuration.setDetectCellType(true);
exporter.setConfiguration(configuration);
exporter.exportReport();
response.getOutputStream().write(xlsxReport.toByteArray());
} catch (JRException e) {
e.printStackTrace();
}
} catch(Exception ex) {
CrmLogger.error(ex);
}
}
I´m facing one problem, I have two jrmxl files. I want to join then in one pdf file, but each in one page.
I saw some tips below but I don´t know if they are the best, because my first file have 3 bands: title, detail and summary. The second have detail and summary.
So I want to keep this format if is possible, because in the summary have the page counter.
I´ve tried this but my second page is blank and have 5 cm of heigth.
List pages = new ArrayList<>();
for (String caminhoRelatorio : caminhoRelatorios) {
reportPath = JasperCompileManager.compileReport(caminhoRelatorio);
reportPage = JasperFillManager.fillReport(reportPath, parameters, ds);
pages.add(reportPage);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JRPdfExporter jrPdfExporter = new JRPdfExporter();
jrPdfExporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, pages);
jrPdfExporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
jrPdfExporter.setParameter(JRPdfExporterParameter.IS_CREATING_BATCH_MODE_BOOKMARKS, Boolean.TRUE);
jrPdfExporter.exportReport();
So what I need to do?
To add multiple JRXMLs in one report/PDF, you can follow the below mentioned way:
Consider the method below to generate a PDF report with 2 JRXMLs which have added in the "jrxmlFileNames" list
public static void reportGenerator(String reportType, List<String> jrxmlFileNames,
Datasource dataSource , String SwapFile)
{
JRConcurrentSwapFile swapFile = new JRConcurrentSwapFile(SwapFile, 102400 , 10);
JRAbstractLRUVirtualizer virtualizer = new JRSwapFileVirtualizer(1000, swapFile, true);
Map<String, JRAbstractLRUVirtualizer> parameters = new HashMap<String, JRAbstractLRUVirtualizer>();
parameters.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
try
{
if (reportType.equalsIgnoreCase("PDF"))
{
try
{
JasperReport jreport1 = JasperCompileManager.compileReport(ReportGenerator.class.getResourceAsStream(jrxmlFileNames.get(0)));
JasperPrint jprint1 = JasperFillManager.fillReport(jreport1, parameters, new JRBeanCollectionDataSource(dataSource.getDataSourceFor1()));
JasperReport jreport2 = JasperCompileManager.compileReport(ReportGenerator.class.getResourceAsStream(jrxmlFileNames.get(1)));
JasperPrint jprint2 = JasperFillManager.fillReport(jreport2, parameters, new JRBeanCollectionDataSource(dataSource.getDataSourceFor2()));
List<JasperPrint> jprintlist = new ArrayList<JasperPrint>();
jprintlist.add(jprint1);
jprintlist.add(jprint2);
String fileName="TESTReport.pdf";
JRExporter exporter = new JRPdfExporter();
exporter.setParameter(JRPdfExporterParameter.JASPER_PRINT_LIST, jprintlist);
exporter.setParameter(JRPdfExporterParameter.OUTPUT_FILE_NAME, fileName);
exporter.exportReport();
}
catch(Exception e)
{
e.printStackTrace();
}
}
swapFile.dispose();
}
catch(Exception e)
{
e.printStackTrace();
}
}
In the above code the following part will help you adding the multiple JRXMLs
List<JasperPrint> jprintlist = new ArrayList<JasperPrint>();
jprintlist.add(jprint1);
jprintlist.add(jprint2);
JRExporter exporter = new JRPdfExporter();
exporter.setParameter(JRPdfExporterParameter.JASPER_PRINT_LIST, jprintlist);
Hope it helps!
To get two pages in report you can use Report group and delete all other bands like detail, summary.
To add report group :-
1:- Open report and in Report inspector right click and select "Add Report Group".
2:- Give any name and choose "Group by the following expression" radio button and leave the expression blank and then Next, select only Report header and then finish.
3:- Now for the second page you can add one more Report Group in the same way.
Here there is a similar question: How do i add a second page on Jaspersoft iReport designer. There is also a simpler way: Put a Page Break component on your Detail Band, which means, drag and drop a 'Break' component, and on the popUp that will get displayed select "Page Break"
I have two JRXML File with two different data source.
in first jasper report data source is JRXmlDataSource and in second jasper report data source is JRResultSetDataSource
try
{
conn= objConnector.getConnection();
conn.setAutoCommit(false);
PreparedStatement ps = conn.prepareCall("{ call Sp_DEMO(?) }");
ps.setString(1,condition);
ResultSet rs = ps.executeQuery();
JasperReport jreport1 = JasperCompileManager.compileReport("d:\\JRXML\\ECGImage.jrxml");
JasperPrint jprint1 = JasperFillManager.fillReport(jreport1, new HashMap(), new JRResultSetDataSource(rs));
jprintlist.add(jprint1);
JasperReport jasperReport = JasperCompileManager.compileReport("d:\\JRXML\\RadiologyReport.jrxml");
JRXmlDataSource xmlDataSource = new JRXmlDataSource("d:\\abc.xml"+, "/X-RayReport/Type");
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, new HashMap(),xmlDataSource);
jprintlist.add(jasperPrint);
File file = new File("d:\\demo.pdf");
if(file.exists())
{
file.delete();
}
JRExporter exporter = new JRPdfExporter();
exporter.setParameter(JRPdfExporterParameter.JASPER_PRINT_LIST, jprintlist);
OutputStream output = new FileOutputStream(new File("d:\\demo.pdf"));
exporter.setParameter(JRPdfExporterParameter.OUTPUT_STREAM, output);
exporter.exportReport();
}
catch(Exception e)
{
e.printStackTrace();
}
i want to create single pdf file as output from both jrxml file.
You can merge the above two pdf like this
List pages = jasperPrint.getPages();
for (int j = 0; j < pages.size(); j++) {
JRPrintPage object = (JRPrintPage)pages.get(j);
jprint1.addPage(object);
}
And jprint1 will be your single output .
Well, that is what JasperReport Subreports are meant to do. You have to create another .jrxml which would be the master report, and include the other existing two in this one as "Subreports". So you'll have a single output.
To create subreports (if you don't know), please refer to these tutoriale: JasperReports - Create SubReports, SubReports.
From the fact that you have two different data sources, I think that you might as well need to read this too: Pass parameter to subreports.
You might need this to pass the different data sources as parameters to the subreports, thus not in your JasperPrint object instance.
I have no factual defence or argumentation about how I do it normally and all that is just matter of personal preference and the ease that I have during the merging and post-processing stages for adding some general additional stuff to the merged report i.e. page numbers, header, footer, etc.
The correct jasper-report way is to stay away from joining reports in Java and instead, to make a main report and then adding subreports to it. However, if you really want to do that in Java, you can use markers and afterwards post-process everything again, check here.
Still, I just don't do that.
Most of the time I prefer to first generate and export different sections of my final report in pdf separately and afterward merge them all together utilizing PDFBox. By not following the jasper report's way, usually I avoid a hell of subreports hierarchy as normally each section of the final report on their own contain couple of other subreports. So, I just find it better to focus on each section separately and later doing the final merging.
I normally do something like this:
public final class Report
{
List<File> MergingFiles;
ReportData data;
public Report(ReportData data)
{
// I prefer to pack all the data like, jrxml files path or
// the data that fills the report in a separate object -> ReportData
this.data = data;
MergingFiles = new ArrayList<>();
}
private void generateCoverPage() throws JRException
{
/* Setting up the data which needs to be passed to cover page
reading the cover page jrxml file
compiling the report */
// and Exporting - I normally use JRPdfExporter for that
exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(data.getCoverPageExportPath()));
exporter.exportReport();
MergingFiles.add(new File(data.getCoverPageExportPath()));
}
private void generateSecondPart() throws JRException
{
/* similar to generateCoverPage() to create another part of the report */
}
public void generateReport()
{
generateCoverPage();
generateSecondPart();
mergePDFFiles(MergingFiles, data.getPrintFileName());
/* Do additional general post process i.e. page numbers, header, footer, etc. here
and then clean up temp files */
}
private void mergePDFFiles(List<File> files, String mergedFileName)
{
// all classes are imported from "org.apache.pdfbox"
try
{
PDFMergerUtility pdfmerger = new PDFMergerUtility();
for (File file : files)
{
PDDocument document;
document = PDDocument.load(file);
pdfmerger.setDestinationFileName(mergedFileName);
pdfmerger.addSource(file);
pdfmerger.mergeDocuments(MemoryUsageSetting.setupTempFileOnly());
document.close();
}
}
catch (IOException e)
{
System.out.println("Error to merge files. Error: " + e.getMessage());
}
}
}
// are just my side notes, however comments surrender with /* */ are the parts which you have to take care of them in case that you wanted to use my approach.
Looked at lots of examples for this, and so far no luck. I'd like to classify free text.
Configure a text classifier. (FilteredClassifier using StringToWordVector and LibSVM)
Train the classifier (add in lots of documents, train on filtered text)
Serialize the FilteredClassifier to disk, quit the app
Then later
Load up the serialized FilteredClassifier
Classify stuff!
It goes ok up to when I try to read from disk and classify things. All the documents and examples show the training list and testing list being built at the same time, and in my case, I'm trying to build a testing list after the fact.
A FilteredClassifier alone is not enough to create a testing Instance with the same "dictionary" as the original training set, so how do I save everything I need to classify at a later date?
http://weka.wikispaces.com/Use+WEKA+in+your+Java+code just says "Instances loaded from somewhere" and doesn't say anything about using a similar dictionary.
ClassifierFramework cf = new WekaSVM();
if (!cf.isTrained()) {
train(cf); // Train, save to disk
cf = new WekaSVM(); // reloads from file
}
cf.test("this is a test");
Ends up throwing
java.lang.ArrayIndexOutOfBoundsException: 2
at weka.core.DenseInstance.value(DenseInstance.java:332)
at weka.filters.unsupervised.attribute.StringToWordVector.convertInstancewoDocNorm(StringToWordVector.java:1587)
at weka.filters.unsupervised.attribute.StringToWordVector.input(StringToWordVector.java:688)
at weka.classifiers.meta.FilteredClassifier.filterInstance(FilteredClassifier.java:465)
at weka.classifiers.meta.FilteredClassifier.distributionForInstance(FilteredClassifier.java:495)
at weka.classifiers.AbstractClassifier.classifyInstance(AbstractClassifier.java:70)
at ratchetclassify.lab.WekaSVM.test(WekaSVM.java:125)
Serialize your Instances which holds the definition of the trained data -similar dictionary?- while you are serializing your classifier:
Instances trainInstances = ... //
Instances trainHeader = new Instances(trainInstances, 0);
trainHeader.setClassIndex(trainInstances .classIndex());
OutputStream os = new FileOutputStream(fileName);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(os);
objectOutputStream.writeObject(classifier);
if (trainHeader != null)
objectOutputStream.writeObject(trainHeader);
objectOutputStream.flush();
objectOutputStream.close();
To desialize:
Classifier classifier = null;
Instances trainHeader = null;
InputStream is = new BufferedInputStream(new FileInputStream(fileName));
ObjectInputStream objectInputStream = new ObjectInputStream(is);
classifier = (Classifier) objectInputStream.readObject();
try { // see if we can load the header
trainHeader = (Instances) objectInputStream.readObject();
} catch (Exception e) {
}
objectInputStream.close();
Use trainHeader to create new Instance:
int numAttributes = trainHeader.numAttributes();
double[] vals = new double[numAttributes];
for (int i = 0; i < numAttributes - 1; i++) {
Attribute attribute = trainHeader.attribute(i);
//If your attribute is nominal or string:
double value = attribute.indexOfValue(myStrVal); //get myStrVal from your source
//If your attribute is numeric
double value = myNumericVal; //get myNumericVal from your source
vals[i] = value;
}
vals[numAttributes] = Instance.missingValue();
Instance instance = new Instance(1.0, vals);
instance.setDataset(trainHeader);
return instance;
try {
//providing path of jrxml to java
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("ReportTemplates/WeeklyReportForCurrentWeek.jrxml");
JasperDesign jdesign = JasperManager.loadXmlDesign(inputStream);
String imgPath = "C:/Users/Sorathiya.Deven/";
//Compile managaer
JasperReport jreport = JasperManager.compileReport(jdesign);
//Run time Report parameters
Map param = new HashMap();
param.put("CurrWeek", new java.math.BigDecimal(week));
param.put("CurrYear", new java.math.BigDecimal(year));
param.put("imgPath", imgPath);
//Fatch Database
Connection con = CreateConnection.makeConnection();
//compile report
JasperPrint jprint=JasperFillManager.fillReport(jreport, param, con);
JRPdfExporter exporterPDF = new JRPdfExporter();
exporterPDF.setParameter(JRExporterParameter.JASPER_PRINT, jprint);
exporterPDF.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, "C:/Users/Sorathiya.Deven/WeeklyReportForCurrentWeek.pdf");
exporterPDF.exportReport();
CreateConnection.closeConnection(con);
} catch (Exception e) {
e.printStackTrace();
}
Hello friends i am using above given code for showing my report containing sub report but when i run this i get report containing blank page does any one tell me whats the actual problem
Your connection is empty.
Please parse sql query then create the report.