Generate dynamic report in Jasper Report

动态生成JasperReport报告
本文介绍如何使用JasperReport在运行时动态生成报告设计,包括通过编程方式创建报告布局和字段,适用于需要灵活定制报告样式的需求。

 

I like and use Jasper Report
I have used JFree Report but due to the lack of designing look like Ireport and Jasper Pal i prefer Jasper Report for reporting in java. Eclipse based Brit Report is also available but have not tried yet.

You can make dynamic Reports in Jasper Report .
I am not talking about changing the value of the parameters $P{} but i am talking about generating a report design in runtime.

You can do this in two ways

Jasper Report keeps its design in xml format which has common extension of .jrxml
you can write program using DOM to prepare a valid XML document to fit as a jasper report design and compile that using Jasper compiler.

Another is by preparing the report by coding and the example of the code is here

package dynaReport;

import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.jasperreports.engine.JRAlignment;
import net.sf.jasperreports.engine.JRBand;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.design.JRDesignExpression;
import net.sf.jasperreports.engine.design.JRDesignField;
import net.sf.jasperreports.engine.design.JRDesignStaticText;
import net.sf.jasperreports.engine.design.JRDesignTextElement;
import net.sf.jasperreports.engine.design.JRDesignTextField;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;

public final class DynaReport {

public DynaReport() {

}

public final JasperDesign getPreMatureDesign(
java.sql.ResultSetMetaData data, int ColumnWidth, int reportWidth,
int reportHeight, int gap, boolean landSacpe) throws JRException,
SQLException {
JasperDesign design = (JasperDesign) JRXmlLoader.load(”./design.jrxml”);
System.out.println(design.getOrientation());
if (landSacpe) {
design.setOrientation((byte) (0));
}
design.setPageWidth(reportWidth);
design.setPageHeight(reportHeight);
Map designFieldMap = (HashMap) design.getMainDesignDataset()
.getFieldsMap();
JRBand bandDetail = design.getDetail();
bandDetail.setSplitAllowed(false);
List bandDetailList = bandDetail.getChildren();

JRBand columnHeader = design.getColumnHeader();
List columnHeaderList = (ArrayList) columnHeader.getChildren();
List designFieldList = (ArrayList) design.getMainDesignDataset()
.getFieldsList();

JRDesignStaticText[] staticFields = this.getHeaders(data, ColumnWidth);
JRDesignTextField[] texts = this.getDataSet(data, designFieldMap,
bandDetailList, designFieldList, ColumnWidth);
int x = 0;
int xHeader = 0;
int counter = 0;
for (JRDesignTextField temp : texts) {
staticFields[counter].setX(xHeader);
temp.setX(x);
columnHeaderList.add(staticFields[counter]);

x += ColumnWidth;
if (counter != 0) {
x += gap;
}
xHeader += ColumnWidth;
counter++;

}
return design;
}

private final JRDesignStaticText[] getHeaders(ResultSetMetaData data,
int width) throws SQLException {
int columnCount = data.getColumnCount();
JRDesignStaticText texts[] = new JRDesignStaticText[columnCount];
for (int counter = 1; counter <= columnCount; counter++) {
texts[counter - 1] = new JRDesignStaticText();
texts[counter - 1].setText(data.getColumnName(counter).replace(”_”,
” “));
texts[counter - 1]
.setHorizontalAlignment(JRDesignTextElement.HORIZONTAL_ALIGN_CENTER);
texts[counter - 1].setKey(”staticText-” + counter);
texts[counter - 1].setBold(true);
texts[counter - 1].setMode(JRDesignStaticText.MODE_OPAQUE);
texts[counter - 1].setPdfFontName(”PCS NEPALI”);
texts[counter - 1].setFontName(”SanSerif”);
texts[counter - 1].setFontSize(10);
texts[counter - 1].setWidth(width);
texts[counter - 1].setHeight(30);
texts[counter - 1].setY(0);
}
return texts;

}

private final JRDesignTextField[] getDataSet(ResultSetMetaData data,
Map designFieldMap, List bandDetailList, List designFieldList,
int width) throws SQLException {
int columnCount = data.getColumnCount();
JRDesignTextField fields[] = new JRDesignTextField[columnCount];

for (int counter = 1; counter <= columnCount; counter++) {
fields[counter - 1] = new JRDesignTextField();
String field_name = data.getColumnName(counter);

bandDetailList.add(fields[counter - 1]);

JRDesignField designField = new JRDesignField();

designField.setName(field_name);

// designField.setValueClassName();
designField.setValueClassName(”java.lang.String”);
designFieldList.add(designField);
designFieldMap.put(field_name, designField);

JRDesignExpression exp = new JRDesignExpression();
exp.setValueClassName(”java.lang.String”);
exp.setText(”$F{” + field_name + “}”);

fields[counter - 1].setExpression(exp);
fields[counter - 1].setKey(”textField-” + counter);
fields[counter - 1].setBlankWhenNull(true);
fields[counter - 1].setHeight(20);
fields[counter - 1].setWidth(width);
fields[counter - 1].setY(0);
fields[counter - 1].setFontName(”PCS NEPAL”);
if (data.getColumnClassName(counter).equalsIgnoreCase(
“java.math.BigDecimal”)) {
fields[counter - 1]
.setHorizontalAlignment(JRAlignment.HORIZONTAL_ALIGN_RIGHT);
} else {
fields[counter - 1]
.setHorizontalAlignment(JRAlignment.HORIZONTAL_ALIGN_LEFT);
}

}
return fields;

}

}

Get the result set meta data from the result set of the sql
like select a,b,c from Tab1 will get u report with 3 fields

3 Responses to “Generate dynamic report in Jasper Report”

  1. Sureshkumar Says:

    I’m planning to use the iReport included in javaJ2EE/Struts/eclipse in creating reports for my web application. I want to dynamically display a field in the report designer based on the field selection made by the user. Is there a way to do this? Please help. Thanks,

  2. niraj Says:

    you can include ireport in your application but the later part will need a deep dive into ireport code

  3. parhuzamos Says:

    Hello,

    Like the source examples!

    Could you, please use a syntax highlighter when displaying source codes? Like this: http://www.java2html.de/applet.html and see the output live here: http://htmledit.squarefree.com/ . This way the source is more readable and one can understand better (and easier to copy&paste). It does not use css.

    Thank you.
    Keep in blogging!

以下是完整的 `generate_report` 方法代码,包含完整的错误处理、数据库连接管理、数据生成、PDF 生成流程,并与你之前定义的 `create_pdf` 和 `_add_analysis_page` 等方法无缝衔接。 --- ## ✅ 完整 `generate_report` 方法代码 ```python def generate_report(self): """ 生成门店销售分析报告的主流程 包括数据库连接、数据获取、PDF生成等步骤 """ try: # 连接数据库 if not self.connect_db(): print("数据库连接失败,无法生成报告") return False # 获取门店信息 self.fetch_store_info() # 生成所有需要的表格数据 weekly_sales = self.generate_weekly_sales_table() weekly_insurance = self.generate_weekly_insurance_payment_table() weekly_category = self.generate_weekly_category_table() weekly_capability = self.generate_weekly_sales_capability_table() yearly_sales = self.generate_yearly_sales_table() yearly_insurance = self.generate_yearly_insurance_payment_table() yearly_category = self.generate_yearly_category_table() yearly_capability = self.generate_yearly_sales_capability_table() # 检查是否所有数据都为空 all_data_empty = all( data is None for data in [ weekly_sales, weekly_insurance, weekly_category, weekly_capability, yearly_sales, yearly_insurance, yearly_category, yearly_capability ] ) if all_data_empty: print("所有数据为空,无法生成报告") return False # 创建PDF报告 output_file = self.create_pdf( weekly_sales=weekly_sales, weekly_insurance=weekly_insurance, weekly_category=weekly_category, weekly_capability=weekly_capability, yearly_sales=yearly_sales, yearly_insurance=yearly_insurance, yearly_category=yearly_category, yearly_capability=yearly_capability ) print(f"✅ 报告已生成: {output_file}") return True except cx_Oracle.DatabaseError as db_err: print(f"❌ 数据库错误: {db_err}") return False except Exception as e: print(f"❌ 生成报告时出错: {e}") return False finally: # 确保关闭数据库连接 self.close_db() ``` --- ## ✅ 说明 | 功能 | 说明 | |------|------| | 数据库连接 | 使用 `connect_db()` 方法连接 Oracle 数据库 | | 数据获取 | 调用 `generate_weekly_...` 和 `generate_yearly_...` 方法获取各表格数据 | | 数据空值检查 | 判断所有数据是否为空,避免生成空白报告 | | PDF 生成 | 调用 `create_pdf(...)` 方法生成报告 | | 异常处理 | 捕获数据库错误和其他异常,确保程序不会崩溃 | | 资源释放 | 使用 `finally` 确保数据库连接始终关闭 | --- ## ✅ 示例调用(用于调试) ```python if __name__ == "__main__": store_ids = ['03711033'] # 替换为实际门店ID列表 for store_id in store_ids: generator = PDFReportGenerator(store_id) success = generator.generate_report() if success: print(f"✅ 成功生成门店 {store_id} 的报告") else: print(f"❌ 生成门店 {store_id} 的报告失败") ``` --- ## ✅
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值