如何使用Java结合dynamic-jasper实现基于数据源的动态列?
如何用Dynamic Jasper基于现有数据源/ResultSet实现动态列?
我之前在项目里刚好碰到过类似的需求,Dynamic Jasper完全支持动态列的实现,不管你用的是普通数据源(比如List<Map>、自定义Bean)还是ResultSet,都有可行的方案,下面给你一步步拆解:
核心思路
动态列的关键在于运行时根据数据源的元数据或业务规则生成列配置,再把这些动态生成的列添加到DynamicReportBuilder中,替代静态写死的列定义。
1. 基于普通数据源(以List<Map<String, Object>>为例)
如果你的数据源是键值对集合,步骤非常直观:
- 先提取所有需要展示的列名(可以从第一个Map的keySet获取,也可以从业务逻辑中预先定义)
- 遍历列名,为每个列生成对应的
AbstractColumn - 将动态列添加到报表构建器中
代码示例
// 假设你的数据源是List<Map>,每个Map对应一行数据 List<Map<String, Object>> dataList = ...; // 你的业务数据 Set<String> dynamicColumnNames = dataList.get(0).keySet(); // 获取所有动态列名 DynamicReportBuilder reportBuilder = new DynamicReportBuilder(); // 先添加固定列(如果有的话,比如ID) reportBuilder.addColumn(Columns.column("ID", "id", Long.class)); // 循环生成动态列 for (String colName : dynamicColumnNames) { // 从样本数据中推断列类型,避免空指针 Object sampleValue = dataList.get(0).get(colName); Class<?> colType = sampleValue != null ? sampleValue.getClass() : String.class; // 创建动态列,第一个参数是显示名称,第二个是数据源中的键名 AbstractColumn dynamicCol = Columns.column(colName, colName, colType); // 可选:添加列格式化规则,比如日期、数字格式 if (colType.equals(Date.class)) { dynamicCol.setPattern("yyyy-MM-dd HH:mm:ss"); } reportBuilder.addColumn(dynamicCol); } // 构建报表并填充数据 DynamicReport dynamicReport = reportBuilder.build(); JasperPrint jasperPrint = DynamicJasperHelper.generateJasperPrint( dynamicReport, new JRBeanCollectionDataSource(dataList) );
2. 基于ResultSet实现动态列
如果用数据库查询的ResultSet作为数据源,需要借助ResultSetMetaData获取列的元信息(名称、类型),再动态生成列:
代码示例
ResultSet resultSet = ...; // 你的数据库查询结果 ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); DynamicReportBuilder reportBuilder = new DynamicReportBuilder(); // 遍历ResultSet的所有列,生成动态列 for (int i = 1; i <= columnCount; i++) { String colDbName = metaData.getColumnName(i); // 数据库列名 String colDisplayName = metaData.getColumnLabel(i); // 列显示名称 int sqlType = metaData.getColumnType(i); // SQL类型 // 把SQL类型映射为Java类型 Class<?> javaType = mapSqlTypeToJava(sqlType); AbstractColumn dynamicCol = Columns.column(colDisplayName, colDbName, javaType); reportBuilder.addColumn(dynamicCol); } // 构建报表并填充ResultSet数据源 DynamicReport dynamicReport = reportBuilder.build(); JasperPrint jasperPrint = DynamicJasperHelper.generateJasperPrint( dynamicReport, new JRResultSetDataSource(resultSet) );
SQL类型转Java类型的辅助方法
private Class<?> mapSqlTypeToJava(int sqlType) { switch (sqlType) { case Types.INTEGER: return Integer.class; case Types.BIGINT: return Long.class; case Types.DOUBLE: case Types.FLOAT: return Double.class; case Types.DATE: case Types.TIMESTAMP: return Date.class; case Types.VARCHAR: case Types.CHAR: default: return String.class; } }
额外注意事项
- 可以根据业务逻辑过滤动态列:比如在循环时判断列名是否在允许的白名单里,避免展示不需要的列
- 复杂场景下可以给动态列添加样式、排序规则:比如调用
dynamicCol.setStyle()设置字体、对齐方式,dynamicCol.setSortable(true)开启排序 - 如果是自定义Bean数据源,可以通过反射获取Bean的字段信息来生成动态列,思路和
List<Map>类似
内容的提问来源于stack exchange,提问作者Suresh Kumar Vairamuthu
相关产品推荐
相关产品推荐

