在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
调用它的方法