在jaspersoft studio中使用多个数据源

根据向Jaspersoft Studio添加自定义数据源,能够将java bean中的自定义数据源添加到报表后,我将使用jasper进入报表的第二点。

我有一个主报告,它使用数据库作为其数据源。 然后我将一个bean.xml数据源添加到报表中,并将一个表添加到主报表中,该报表使用此bean.xml数据源来获取java bean。

我的目标是从主报表中获取字段值并操纵其值,然后用这些值填充bean,最后用bean填充表。

为此,我编写了3个类,我在表数据集中用作Scriptlet

这是我需要做的事情的说明: 在此处输入图像描述

问题出在FillTable类中,当我使用String kNFormelGG = (String) this.getParameterValue("gg"); 创建的bean.xml使用java.lang.reflect.InvocationTargetException的测试连接失败

 Caused by: java.lang.NullPointerException at net.sf.jasperreports.engine.JRAbstractScriptlet.getParameterValue(JRAbstractScriptlet.java:95) at net.sf.jasperreports.engine.JRAbstractScriptlet.getParameterValue(JRAbstractScriptlet.java:86) at org.iqtig.reporting.dataSource.bean.dataSourceXML.FillTable.fillTable(FillTable.java:45) at org.iqtig.reporting.dataSource.bean.dataSourceXML.JRDataSourceFactory.createCollection(JRDataSourceFactory.java:27) ... 34 more 

如果我分配一个修复值,如String kNFormelGG ="Test me"则bean连接不会遇到任何错误,并且在将bean.xml指定为Dataset1中的Default Data Adapter的值后,它会使用静态值填充表。 如何从主报表数据源动态获取参数或值中的数据并在bean中使用它? 我有这样的假设:在从我的适配器调用静态工厂类时,字段仍然是空的。 也许我错了,但我没有找到任何其他声明来解决这个问题。

BeanFactory类

 import java.util.Collection; import net.sf.jasperreports.engine.JRDefaultScriptlet; import net.sf.jasperreports.engine.JRScriptletException; /** * Factory for TableCellsBean Klasse * * @author iman.gharib */ public class JRDataSourceFactory extends JRDefaultScriptlet { /** * @return collection der TableCellsBean Objekten * @throws JRScriptletException */ public static Collection createCollection() throws JRScriptletException { FillTable ft = new FillTable(); Collection reportRows = ft.fillTable(); return reportRows; } } 

豆类

 public class TableCellsBean { private String fieldName; private String keyFormel; private String mK; private String notation; private String item; /** * Constructor. * * @param fieldName * @param keyFormel * @param mK * @param notation * @param item */ public TableCellsBean(final String fieldName, final String keyFormel, final String mK, final String notation, final String item) { this.fieldName = fieldName; this.keyFormel = keyFormel; this.mK = mK; this.notation = notation; this.item = item; } /** * Constructo Leer */ public TableCellsBean() { } public TableCellsBean getme() { return this; } // getter and setters } 

用于准备和创建bean的类

 public class FillTable extends JRDefaultScriptlet { @Override public void afterColumnInit() throws JRScriptletException { fillTable(); } public ArrayList splitGGArray(final String kNFormelGG) { ArrayList fieldNames = new ArrayList(); String[] array = (kNFormelGG.split(" ")); for (String sub : array) { fieldNames.add(sub); } return fieldNames; } public Collection fillTable() throws JRScriptletException { // gg is a parameter for table dataset. It is mapped to KN_FormelGG // which comes from the main report data base String kNFormelGG = (String) this.getParameterValue("gg"); List listTableCells = new ArrayList(); // TableCellsBean tableCell = new TableCellsBean(); for (String fn : splitGGArray(kNFormelGG)) { listTableCells.add(new TableCellsBean(fn, fn, fn, fn, fn)); // listTableCells.add(tableCell); } // JRBeanCollectionDataSource tableCellJRBean = new JRBeanCollectionDataSource(listTableCells); // Map parameters = new HashMap(); // parameters.put("FieldDataSource", tableCellJRBean); return listTableCells; } } 

JRXML

                                                                                                                                                                                                          

我的目标是从主报表中获取字段值并操纵其值,然后用这些值填充bean,最后用bean填充表。

我将忽略所有的scriplets和其他代码,并向您展示使用当前字段,变量或参数值为另一个组件创建动态数据源的最简单方法。

例如,我们将在field1(row1,row2)中包含这些String值

 Test1_1.23:Test2_4.32:Test3_1.08 Test1_2.12:Test2_5.12:Test3_2.13 

我们想要拆分:并创建行(Bean列表),然后拆分_以创建列(bean上的属性)并在jr:table组件中显示它。

java代码(或Bean)

 public class TableCellsBean { private String name; private double value; public TableCellsBean(String name,double value){ this.name = name; this.value = value; } public static JRBeanCollectionDataSource getDatasource(String fieldValue){ List retList = new ArrayList<>(); String[] values = fieldValue.split(":"); for (String v : values) { String[] sp = v.split("_"); retList.add(new TableCellsBean(sp[0], Double.parseDouble(sp[1]))); } return new JRBeanCollectionDataSource(retList); } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getValue() { return value; } public void setValue(double value) { this.value = value; } } 

正如您在此bean类中已经看到的那样,我添加了一个静态方法,该方法根据作为参数传递的值返回JRBeanCollectionDataSource

基本上你将fieldValue传递给这个方法,它做了一些逻辑,创建了TableCellBean ,将它们添加到list并返回一个JRBeanCollectionDataSource

注意:该方法不需要是静态的,也不需要在此类中,此外不考虑exception处理。

报告 – jrxml

在示例中,我们将在第1行包含Test1_1.23:Test2_4.32:Test3_1.08在第2行包含Test1_1.23:Test2_4.32:Test3_1.08

我们定义一个表示TableCellsBean的子数据集

     

作为数据源,我们调用静态方法传递当前行中的field1内容。

  

完整的jrxml

                                                                  

测试这个例子

添加主要方法导出为pdf

 public static void main(String[] args) throws JRException { //Compile report JasperReport report = JasperCompileManager.compileReport("myJasperReport.jrxml"); //Setting up some arbitrary data to test the auto creation of datasource List someData = new ArrayList<>(); someData.add("Test1_1.23:Test2_4.32:Test3_1.08"); someData.add("Test1_2.12:Test2_5.12:Test3_2.13"); //Fill report JasperPrint jasperPrint = JasperFillManager.fillReport(report, new HashMap<>(),new JRBeanCollectionDataSource(someData)); //Export to pdf JRPdfExporter exporter = new JRPdfExporter(); exporter.setExporterInput(new SimpleExporterInput(jasperPrint)); exporter.setExporterOutput(new SimpleOutputStreamExporterOutput("myJasperReport.pdf")); SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration(); exporter.setConfiguration(configuration); exporter.exportReport(); } 

产量

结果

结论

根据运行的报告值(字段,变量,参数)为组件提供自定义数据源的最简单方法是创建一个生成数据源并在dataSourceExpression调用它的方法