How to dynamically add multiple pieces of data in

2019-09-06 17:50发布

问题:

I have a Jasper Report I am working on in Java.

In Java I can dynamically populate a bean with data with the following code:

    List<ThemeBean> themes = new ArrayList<ThemeBean>();
    CSVReader csvReader = new CSVReader(new FileReader(csvFilename));
    List<String[]> data = csvReader.readAll();
    for(String[] d : data) {
        ThemeBean tb = new ThemeBean();
        tb.setThemes(d[0]);
        tb.setComments(d[1]);
        tb.setSentiment(d[2]);
        themes.add(tb);
    }   
        JasperDesign jasperDesign = JRXmlLoader.load(fileName);
        JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(themes);
        JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, null, ds);

This works well when the .jrxml file has the correct fields specified and textFieldExpression within the tags...

The following gets dynamically populated with the List that was built:

<textFieldExpression><![CDATA[$F{themes}]]></textFieldExpression>

My problem is figuring out how to do this Dynamically for two different tables in the same report. It seems that I can only use for one iteration of data to be dynamically added. I am trying to achieve a result where I have two completely different tables generated within the same report. If this question isn't clear, please let me know and I will attempt to fix it. Thanks.

回答1:

You can pass multiple bean collections to a report by creating another bean that holds a beanCollection. Such a bean would look like this:

public class DataBean {
    private Collection beanCollection = null;

    public DataBean() {
    }

    public Collection getBeanCollection() {
        return beanCollection;
    }

    public void setBeanCollection(Collection beanCollection) {
        this.beanCollection = beanCollection;
    }
}

I assume that the other collection will be of a different type than ThemeBean. I'm using FruitBean as an example. For each bean collection you want to pass, you create a DataBean and add it to a collection, then pass that collection to the report. So your code would change to be something like this:

List<DataBean> allData = new ArrayList<DataBean>();

//...Create and populate `List<ThemeBean> themes`

DataBean db = new DataBean();
db.setBeanCollection(themes);
allData.add(db);

//...Create and populate `List<FruitBean> fruits`

db = new DataBean();
db.setBeanCollection(fruits);
allData.add(db);

//... Load the report
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(allData);
//... Fill the report

The report that you fill with this datasource will be a shell report, containing a subreport for each DataBean you created. There will only be one field available in this report: $F{beanCollection}

Set the datasource expression of the subreport(s) to

new JRBeanCollectionDataSource($F{beanCollection}).

The fields for ThemeBean or FruitBean will then be available within the subreport.

If you prefer to use list components instead of subreports, that would also work.



回答2:

Jasper ideology: one report - one DataSource.

Use 2 subreport in main report. Main.jrxml contains subreport1 (for display List<ThemeBean>) and subreport2 (for List<AnotherBean>). Subreport1 and Subreport2 put into Title (or Summary) band.

Define parameters in Main.jrxml : themesPar, anotherPar as java.util.Collection

Put collection as parameters into main report:

List<ThemeBean> themes = new ArrayList<ThemeBean>();
themes.add(...);
...
List<AnotherBean> blablas = new ArrayList<AnotherBean>();
blablas.add(...);
...

HashMap<String, Object> parameters = new HashMap<String, Object>();
parameters.put("themesPar", themes);
parameters.put("anotherPar", blablas);

JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, new JREmptyDataSource());

For subreport1 Data Source Expression in main report write like

new JRBeanCollectionDataSource($P{themesPar})

and use the same way with $P{anotherPar} for subreport2. In both cases set for subreports

Connection Type = "Use a datasource expression"

Why any novice ask this question??? :) Why this solution not present in jasperforge FAQ?



回答3:

Jasper ideology: one report - one DataSource.

Use 2 subreport in main report. Main.jrxml contains subreport1 (for display List) and subreport2 (for List). Subreport1 and Subreport2 put into Title (or Summary) band.

Define parameters in Main.jrxml : themesPar, anotherPar as java.util.Collection