Skip to content

Instantly share code, notes, and snippets.

@nvurgaft
Last active December 15, 2020 09:09
Show Gist options
  • Save nvurgaft/2ebefbf7c2acca78f975f773da7d0baa to your computer and use it in GitHub Desktop.
Save nvurgaft/2ebefbf7c2acca78f975f773da7d0baa to your computer and use it in GitHub Desktop.
An example class that uses DynamicReports to generate demo a report with subreports and a timechart
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.sf.dynamicreports.jasper.builder.JasperReportBuilder;
import net.sf.dynamicreports.report.base.expression.AbstractSimpleExpression;
import static net.sf.dynamicreports.report.builder.DynamicReports.cht;
import static net.sf.dynamicreports.report.builder.DynamicReports.cmp;
import static net.sf.dynamicreports.report.builder.DynamicReports.col;
import static net.sf.dynamicreports.report.builder.DynamicReports.report;
import static net.sf.dynamicreports.report.builder.DynamicReports.stl;
import static net.sf.dynamicreports.report.builder.DynamicReports.type;
import net.sf.dynamicreports.report.builder.chart.CategoryChartSerieBuilder;
import net.sf.dynamicreports.report.builder.chart.TimeSeriesChartBuilder;
import net.sf.dynamicreports.report.builder.column.TextColumnBuilder;
import net.sf.dynamicreports.report.builder.component.SubreportBuilder;
import net.sf.dynamicreports.report.builder.style.FontBuilder;
import net.sf.dynamicreports.report.constant.TimePeriod;
import net.sf.dynamicreports.report.datasource.DRDataSource;
import net.sf.dynamicreports.report.definition.ReportParameters;
import net.sf.dynamicreports.report.exception.DRException;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JREmptyDataSource;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
/**
*
* @author Nick Vurgaft
*/
public class ReportTest {
private Connection connection;
public void start() {
try {
Class.forName("org.hsqldb.jdbcDriver");
connection = DriverManager.getConnection("jdbc:hsqldb:mem:test");
createTables();
build();
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
}
private void createTables() throws SQLException {
Statement st = connection.createStatement();
st.execute("CREATE TABLE sales (item VARCHAR(50), quantity INTEGER, unitprice INTEGER, orderdate DATE NOT NULL)");
st.execute("INSERT INTO sales(item, quantity, unitprice, orderdate) VALUES ('Book', 5, 100, DATE '2090-07-08')");
st.execute("INSERT INTO sales(item, quantity, unitprice, orderdate) VALUES ('Cup', 12, 25, DATE '2090-07-08')");
st.execute("INSERT INTO sales(item, quantity, unitprice, orderdate) VALUES ('Book', 1, 110, DATE '2090-07-09')");
st.execute("INSERT INTO sales(item, quantity, unitprice, orderdate) VALUES ('Cup', 22, 25, DATE '2090-07-09')");
st.execute("INSERT INTO sales(item, quantity, unitprice, orderdate) VALUES ('Book', 8, 110, DATE '2090-07-10')");
st.execute("INSERT INTO sales(item, quantity, unitprice, orderdate) VALUES ('Cup', 22, 20, DATE '2090-07-10')");
st.execute("INSERT INTO sales(item, quantity, unitprice, orderdate) VALUES ('Book', 12, 120, DATE '2090-07-11')");
st.execute("INSERT INTO sales(item, quantity, unitprice, orderdate) VALUES ('Cup', 18, 20, DATE '2090-07-11')");
st.execute("CREATE TABLE inventory (item VARCHAR(50), quantity INTEGER, code INTEGER)");
st.execute("INSERT INTO inventory VALUES('Book', 200, 42)");
st.execute("INSERT INTO inventory VALUES('Cup', 400, 43)");
}
private void build() {
// define cloumn's name to type mapping
Pair<String, Class<Date>> orderdate = new ImmutablePair<>("orderdate", Date.class);
Pair<String, Class> item = new ImmutablePair<>("item", String.class);
Pair<String, Class> code = new ImmutablePair<>("code", Integer.class);
Pair<String, Class> quantity = new ImmutablePair<>("quantity", Integer.class);
Pair<String, Class> unitprice = new ImmutablePair<>("unitprice", Integer.class);
SubreportBuilder subreport1 = cmp.subreport(new SubreportExpression(orderdate, item, quantity, unitprice))
.setDataSource(new SubreportDataSourceExpression("SELECT item, quantity, unitprice, orderdate FROM sales"));
SubreportBuilder subreport2 = cmp.subreport(new SubreportExpression(null, item, quantity, code))
.setDataSource(new SubreportDataSourceExpression("SELECT item, quantity, code FROM inventory"));
try {
report()
.detail(subreport1, cmp.verticalGap(20))
.detail(subreport2, cmp.verticalGap(20))
.setDataSource(createDataSource())
.show();
} catch (DRException e) {
e.printStackTrace();
}
}
private JRDataSource createDataSource() {
// the detail bands contain subreports each with their own datasource.
// so the empty datasource acts as a placeholder for the details data,
// without the empty datasource no details will be printed.
return new JREmptyDataSource(1);
}
private class SubreportExpression extends AbstractSimpleExpression<JasperReportBuilder> {
private static final long serialVersionUID = 1L;
private Pair<String, Class<Date>> datetimeColumn;
private Pair<String, Class>[] columns;
public SubreportExpression(Pair<String, Class<Date>> datetimeColumn, Pair<String, Class>... columns) {
this.datetimeColumn = datetimeColumn;
this.columns = columns;
}
@Override
public JasperReportBuilder evaluate(ReportParameters reportParameters) {
int masterRowNumber = reportParameters.getReportRowNumber();
JasperReportBuilder report = report();
report.title(cmp.text("Subreport" + masterRowNumber));
for (Pair<String, Class> column : this.columns) {
report.addColumn(col.column(column.getKey(), column.getKey().toUpperCase(), column.getValue()));
}
if (datetimeColumn != null) {
report.summary(buildTimeSeriesLineChart(datetimeColumn, columns));
report.addColumn(col.column(datetimeColumn.getKey(), datetimeColumn.getKey().toUpperCase(), type.dateYearToMonthType()));
}
return report;
}
private TimeSeriesChartBuilder buildTimeSeriesLineChart(
Pair<String, Class<Date>> datetimeColumn,
Pair<String, Class>[] valueColumns) {
FontBuilder boldFont = stl.fontArialBold().setFontSize(12);
TextColumnBuilder<Date> orderDateColumn = col.column(
datetimeColumn.getKey(),
datetimeColumn.getKey().toUpperCase(),
type.dateYearToMonthType());
// time chart serie need to have numeric values
CategoryChartSerieBuilder[] _columns = Stream.of(valueColumns)
.filter((c) -> Number.class.isAssignableFrom(c.getValue()))
.map((c) -> col.column(c.getKey(), c.getKey().toUpperCase(), c.getValue()))
.map((c) -> cht.serie(c))
.collect(Collectors.toList())
.toArray(new CategoryChartSerieBuilder[0]);
return cht.timeSeriesChart()
.setTitle("Time series chart")
.setTitleFont(boldFont)
.setTimePeriod(orderDateColumn)
.setTimePeriodType(TimePeriod.DAY)
.series(_columns)
.setTimeAxisFormat(
cht.axisFormat().setLabel("Date"));
}
}
private class SubreportDataSourceExpression extends AbstractSimpleExpression<JRDataSource> {
private static final long serialVersionUID = 1L;
private String sqlQuery;
public SubreportDataSourceExpression(String sqlQuery) {
this.sqlQuery = sqlQuery;
}
@Override
public JRDataSource evaluate(ReportParameters reportParameters) {
try (PreparedStatement stmnt = connection.prepareStatement(sqlQuery)) {
try (ResultSet rs = stmnt.executeQuery()) {
ResultSetMetaData rsmd = rs.getMetaData();
String[] columns = new String[rsmd.getColumnCount()];
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
columns[i - 1] = rsmd.getColumnName(i);
}
DRDataSource dataSource = new DRDataSource(columns);
while (rs.next()) {
Object[] values = new Object[rsmd.getColumnCount()];
for (int j = 1; j <= rsmd.getColumnCount(); j++) {
values[j - 1] = rs.getObject(j);
}
dataSource.add(values);
}
return dataSource;
}
} catch (Throwable ee) {
ee.printStackTrace();
}
return null;
}
}
public static void main(String[] args) {
ReportTest reportTest = new ReportTest();
reportTest.start();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment