DynamicJasper - How to add a subreport as columns?

2019-02-19 02:31发布

问题:

Overview

  • I have a Java class which has an ArrayList that must be printed to the jasperReport as a subreport.

  • I'm using DynamicJasper library.

  • The example on this question has been modified so it can be reproduced. However the data is different on the real case.

Problem

The current code Ive come with, prints the subreport in another line. Its ugly. I wanted the subreport to just be a group of columns that are concatenated.

To make it clear, here's the current result

And What I want is something like this:

Current code

public class Test_subReport {

    protected static JasperPrint jp;
    protected static JasperReport jr;
    protected static Map params = new HashMap();
    protected static DynamicReport dr;

    public static void main(String args[]) throws SQLException, ColumnBuilderException, ClassNotFoundException {

        Test_subReport t = new Test_subReport();
        t.createReport();

    }

    public void createReport() throws SQLException, ColumnBuilderException, ClassNotFoundException {

        ArrayList<Fruit> createMockDataset = createMockDataset();

        Style titleStyle = new Style();
        titleStyle.setHorizontalAlign(HorizontalAlign.CENTER);
        titleStyle.setFont(Font.ARIAL_SMALL_BOLD);

        Style dataStyle = new Style();
        dataStyle.setHorizontalAlign(HorizontalAlign.CENTER);
        dataStyle.setFont(Font.ARIAL_SMALL);
        dataStyle.setBlankWhenNull(true);

        final List items = SortUtils.sortCollection(createMockDataset, Arrays.asList(new String[]{"name", "description"}));

        FastReportBuilder drb = new FastReportBuilder();
        drb.setTemplateFile("templatePortrait.jrxml", true, true, true, true);
        drb.addColumn("name", "name", String.class.getName(), 30, dataStyle)
                .addColumn("description", "description", String.class.getName(), 50, dataStyle)
                .setTitle("Report")
                .setSubtitle("")
                .setPrintBackgroundOnOddRows(true)
                .setUseFullPageWidth(true);

        drb.addGroups(2);
        try {
            drb.addField("evaluations", List.class.getName());
            drb.addSubreportInGroupHeader(1, createSubreport("Evaluations"));
        } catch (Exception ex) {
            Logger.getLogger(Test_subReport.class.getName()).log(Level.SEVERE, null, ex);
        }

        DynamicReport dynamicReport = drb.build();

        dynamicReport.setTitleStyle(titleStyle);

        HashMap parametros = new HashMap();
        parametros.put("dataRelatorio", MyTools.getDataPorExtenso());

        doReport(dynamicReport, items, parametros);
    }

    public void doReport(final DynamicReport _report, final Collection _data, HashMap parametros) {
        try {
            JRDataSource beanCollectionDataSource = new JRBeanCollectionDataSource(_data);

            JasperPrint jasperPrint = DynamicJasperHelper.generateJasperPrint(_report, new ClassicLayoutManager(), beanCollectionDataSource, parametros);

            JasperViewer.viewReport(jasperPrint);
        } catch (JRException ex) {
            ex.printStackTrace();
        }
    }

    private DynamicReport createHeaderSubreport(String title) throws Exception {
        FastReportBuilder rb = new FastReportBuilder();
        DynamicReport dr = rb
                .addColumn("id", "id", Integer.class.getName(), 100)
                .addColumn("score", "score", Double.class.getName(), 50)
                .setMargins(5, 5, 20, 20)
                .setUseFullPageWidth(true)
                .setWhenNoDataNoPages()
                .setTitle(title)
                .build();
        return dr;
    }

    private Subreport createSubreport(String title) throws Exception {
        SubReportBuilder srb = new SubReportBuilder();
        srb.setDynamicReport(createHeaderSubreport(title), new ClassicLayoutManager())
                .setStartInNewPage(true)
                .setDataSource(DJConstants.DATA_SOURCE_ORIGIN_FIELD, DJConstants.DATA_SOURCE_TYPE_COLLECTION, "evaluations");
        return srb.build();
    }

    public ArrayList<Fruit> createMockDataset() {
        ArrayList<Fruit> fruits = new ArrayList<>();

        Fruit f1 = new Fruit();
        f1.name = "Apple X1";
        f1.description = "Yummy yummy apple for the stackoverflow readers 1";

        Fruit f2 = new Fruit();
        f2.name = "Apple Ag";
        f2.description = "Yummy yummy apple for the stackoverflow readers 2";

        Fruit f3 = new Fruit();
        f3.name = "Apple Mn";
        f3.description = "Yummy yummy apple for the stackoverflow readers 3";

        Fruit f4 = new Fruit();
        f4.name = "Apple O2";
        f4.description = "Yummy yummy apple for the stackoverflow readers 4";

        //Evaluations for f1
        for (int i = 0; i < 4; i++) {
            Evaluation e = new Evaluation();
            e.id = i;
            e.score = Math.random() * 10;
            f1.evaluations.add(e);
        }

        //evaluations for f4
        for (int i = 0; i < 4; i++) {
            Evaluation e = new Evaluation();
            e.id = i;
            e.score = Math.random() * 10;
            f4.evaluations.add(e);
        }

        fruits.add(f1);
        fruits.add(f2);
        fruits.add(f3);
        fruits.add(f4);

        return fruits;

    }

    public class Fruit {

        public String name;
        public String description;
        public ArrayList<Evaluation> evaluations = new ArrayList<Evaluation>();

        public Fruit() {

        }

        public Fruit(String name, String description) {
            this.name = name;
            this.description = description;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public ArrayList<Evaluation> getEvaluations() {
            return evaluations;
        }

        public void setEvaluations(ArrayList<Evaluation> evaluations) {
            this.evaluations = evaluations;
        }

    }

    public class Evaluation {

        public int id;
        public double score;

        public Evaluation() {

        }

        public Evaluation(int id, double score) {
            this.id = id;
            this.score = score;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public double getScore() {
            return score;
        }

        public void setScore(double score) {
            this.score = score;
        }

    }

}

回答1:

Probably there isn't way to implement desired behavior using subreports.

I guess, that the best way to do it is to use just groups, but data model should be a bit modified for that.

Here is my solution:

public class Test_subReport {

    protected static JasperPrint jp;
    protected static JasperReport jr;
    protected static Map params = new HashMap();
    protected static DynamicReport dr;

    public static void main(String args[]) throws SQLException, ColumnBuilderException, ClassNotFoundException {

        Test_subReport t = new Test_subReport();
        t.createReport();

    }

    public void createReport() throws SQLException, ColumnBuilderException, ClassNotFoundException {

        List<DataWrapper> createMockDataset = wrapData(createMockDataset());

        Style titleStyle = new Style();
        titleStyle.setHorizontalAlign(HorizontalAlign.CENTER);
        titleStyle.setFont(Font.ARIAL_SMALL_BOLD);

        Style dataStyle = new Style();
        dataStyle.setHorizontalAlign(HorizontalAlign.CENTER);
        dataStyle.setFont(Font.ARIAL_SMALL);
        dataStyle.setBlankWhenNull(true);

        final List items = SortUtils.sortCollection(createMockDataset, Arrays.asList(new String[]{"name", "description"}));

        FastReportBuilder drb = new FastReportBuilder();
        drb.setTemplateFile("templatePortrait.jrxml", true, true, true, true);
        drb.addColumn("name", "name", String.class.getName(), 30, dataStyle)
                .addColumn("description", "description", String.class.getName(), 100, dataStyle)
                .addColumn("id", "id", Integer.class.getName(), 30, dataStyle)
                .addColumn("score", "score", Double.class.getName(), 30, false, "$ #.00", dataStyle)
                .setTitle("Report")
                .setWhenNoDataNoPages()
                .setAllowDetailSplit(false)
                .setUseFullPageWidth(true);

        drb.addGroups(2);

        DynamicReport dynamicReport = drb.build();
        dynamicReport.setTitleStyle(titleStyle);

        HashMap parametros = new HashMap();
        parametros.put("dataRelatorio", MyTools.getDataPorExtenso());

        doReport(dynamicReport, items, parametros);
    }

    public void doReport(final DynamicReport _report, final Collection _data, HashMap parametros) {
        try {
            JRDataSource beanCollectionDataSource = new JRBeanCollectionDataSource(_data);

            JasperPrint jasperPrint = DynamicJasperHelper.generateJasperPrint(_report, new ClassicLayoutManager(), beanCollectionDataSource, parametros);

            JasperViewer.viewReport(jasperPrint);
        } catch (JRException ex) {
            ex.printStackTrace();
        }
    }

    public List<DataWrapper> wrapData(List<Fruit> fruits) {
        List<DataWrapper> dataList = new ArrayList<>();

        for (Fruit fruit : fruits) {

            if (fruit.getEvaluations().isEmpty()) {
                dataList.add(new DataWrapper(fruit.name, fruit.description, null, null));
            } else {
                for (Evaluation evaluation : fruit.getEvaluations()) {
                    dataList.add(new DataWrapper(fruit.name, fruit.description, evaluation.id, evaluation.score));
                }
            }
        }

        return dataList;
    }

    public List<Fruit> createMockDataset() {
        ArrayList<Fruit> fruits = new ArrayList<>();

        Fruit f1 = new Fruit();
        f1.name = "Apple X1";
        f1.description = "Yummy yummy apple for the stackoverflow readers 1";

        Fruit f2 = new Fruit();
        f2.name = "Apple Ag";
        f2.description = "Yummy yummy apple for the stackoverflow readers 2";

        Fruit f3 = new Fruit();
        f3.name = "Apple Mn";
        f3.description = "Yummy yummy apple for the stackoverflow readers 3";

        Fruit f4 = new Fruit();
        f4.name = "Apple O2";
        f4.description = "Yummy yummy apple for the stackoverflow readers 4";

        //Evaluations for f1
        for (int i = 0; i < 4; i++) {
            Evaluation e = new Evaluation();
            e.id = i;
            e.score = Math.random() * 10;
            f1.evaluations.add(e);
        }

        //evaluations for f4
        for (int i = 0; i < 4; i++) {
            Evaluation e = new Evaluation();
            e.id = i;
            e.score = Math.random() * 10;
            f4.evaluations.add(e);
        }

        fruits.add(f1);
        fruits.add(f2);
        fruits.add(f3);
        fruits.add(f4);

        return fruits;
    }

    public class Fruit {

        public String name;
        public String description;
        public ArrayList<Evaluation> evaluations = new ArrayList<Evaluation>();

        public Fruit() {

        }

        public Fruit(String name, String description) {
            this.name = name;
            this.description = description;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public ArrayList<Evaluation> getEvaluations() {
            return evaluations;
        }

        public void setEvaluations(ArrayList<Evaluation> evaluations) {
            this.evaluations = evaluations;
        }

    }

    public class Evaluation {

        public int id;
        public double score;

        public Evaluation() {

        }

        public Evaluation(int id, double score) {
            this.id = id;
            this.score = score;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public double getScore() {
            return score;
        }

        public void setScore(double score) {
            this.score = score;
        }

    }

    public class DataWrapper {

        public String name;
        public String description;

        public Integer id;
        public Double score;

        public DataWrapper() {

        }

        public DataWrapper(String name, String description, Integer id, Double score) {
            this.name = name;
            this.description = description;
            this.id = id;
            this.score = score;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public Double getScore() {
            return score;
        }

        public void setScore(Double score) {
            this.score = score;
        }
    }

}

And here is the result:

Feel free to ask if you have some question.