如何以二开的方式引出Excel并自定义样式

小编有话说
在客户的实际业务中,经常需要引出报表或动态表单的数据,并且对引出数据的表格样式有个性化需求,比如添加标题行、调整单元格高度、单元格背景色、文字字体/颜色/字号等等。目前苍穹提供的报表引出插件暂不支持引出表格个性化样式的实现。
因此,本篇文章介绍如何通过纯二开的方式,帮助客户实现引出表格数据的个性化样式需求。
1 案例背景
客户系统有两张单据:水果单和化肥单,需要把这两张单据的数据引出到Excel表格中。
水果单据的关键字段有【产品类型】(下拉列表)、【产地】(基础资料)、【水果名称】(单据体文本),如下图所示:

图1-水果单据示例
化肥单据的关键字段有【肥料名称】(文本)、【产地】(基础资料),如下图所示:

图2-化肥单据示例
两张单据的列表数据如下:

图3-水果列表数据示例

图4-化肥列表数据示例
报表和引出数据都需要对2张单据进行查询,需要实现引出的效果如下:

图5-报表实现按钮示例

图6-引出Excel示例
2 解决方案
2.1 方案整体思路
在这个方案的设计过程中,报表和引出数据都需要对2张单据进行查询,并利用文件服务提供下载功能。
同时,把查询和引出的代码与报表插件剥离,放到工具类中,做到代码复用,方便后续将该方案迁移到其他业务场景中使用。
整体二开流程如下:
1. 新建报表页面,设计报表,注册报表插件;
2. 抽取查询数据公共代码,编写查询数据工具类;
3. 编写报表取数插件,查询数据展示在报表上;
4. 编写报表界面插件,实现引出Excel文件,并修改Excel样式。
2.2 二开步骤详解
步骤1:新建报表页面,注册报表取数插件和报表页面插件
在【开发平台】表单设计器中,设计报表页面,并注册报表取数插件和报表页面插件,如下图所示:

图7-设计报表列表字段

图8-注册报表取数插件

图9-注册报表页面插件
步骤2:编写查询数据工具类
查询数据的代码,是引出的数据源,同时也是报表的数据源,这一部分的逻辑写在一个工具类中,共用代码。
使用QueryServiceHelper查询数据,将2个DateSet对象用join进行合并,代码如下:
public class FPQueryUtil {
public static DataSet queryData() {
DataSet dataSetFruits = QueryServiceHelper.queryDataSet("FruitPro", "kdec_fruit_bill",
"id, billno as kdec_fnumber, kdec_entryentity.kdec_fruits as kdec_fname, kdec_fruit_type, kdec_fruit_pro.id as proid, kdec_fruit_pro.name as kdec_pro", null, "");
DataSet dataSet2 = dataSetFruits.copy();
Iterator<Row> iterator = dataSet2.iterator();
List proList = new ArrayList<>();
while (iterator.hasNext()) {
Row row = iterator.next();
proList.add(row.get("proid"));
}
QFilter regionFilter = new QFilter("kdec_region", QCP.in, proList);
QFilter statusFilter = new QFilter("billstatus", QCP.like, "C");
DataSet dataSetFertilizer = QueryServiceHelper.queryDataSet("FruitPro", "kdec_fertilizer_bill",
"id, billno as kdec_fernumber, kdec_name as kdec_fername, kdec_region", new QFilter[]{regionFilter,statusFilter}, "");
DataSet result = dataSetFruits.rightJoin(dataSetFertilizer)
.select(new String[]{"kdec_fnumber", "kdec_fname", "kdec_pro", "kdec_fruit_type"}, new String[]{"kdec_fernumber", "kdec_fername"})
.on("proid", "kdec_region").finish();
return result;
}
}步骤3:编写报表取数插件
报表取数插件实现代码如下:
public class FruitProReportListDataPlugin extends AbstractReportListDataPlugin {
@Override
public DataSet query(ReportQueryParam reportQueryParam, Object o) throws Throwable {
return FPQueryUtil.queryData();
}
}步骤4:编写报表界面插件,引出Excel文件并修改样式
首先,监听按钮点击。调用以下代码,查询数据,构建Excel文件,弹出下载链接。代码如下:
@Override
public void itemClick(ItemClickEvent evt) {
super.itemClick(evt);
switch (evt.getItemKey()) {
case "kdec_export": {
// 第一行标题
String title = "水果生产以及产地";
// 调用查询工具类,获取数据源对象DataSet
DataSet dataSet = FPQueryUtil.queryData();
// excelList用于提供数据源给 excel工作簿,外层的list是行,里面的List<String>是列,存储value
List<List<String>> excelList = getExcelList(dataSet);
// 创建excel工作簿
XSSFWorkbook workbook = MyExportUtil.reportExcel(excelList, title);
// 上传
String path = MyExportUtil.upload(title, workbook);
// 弹出提示框
getView().showMessage("下载文件链接:"+ RequestContext.get().getClientFullContextPath() + "/attachment/download.do?path=" + path);
}
break;
}
}接着,解析DataSet,构建数据集合。构建第二行表头,解析DataSet,构建List对象,为即将引出的excel提供数据源,代码如下:
public List<List<String>> getExcelList (DataSet dataSet) {
// excelList用于提供数据源给 excel工作簿,外层的list是行,里面的List<String>是列,存储value
List<List<String>> excelList = new ArrayList<>();
List<String> titles = new ArrayList<>();
titles.add("水果编码");
titles.add("水果名称");
titles.add("产地");
titles.add("化肥编码");
titles.add("化肥名称");
excelList.add(titles);
while (dataSet.hasNext()) {
Row row = dataSet.next();
List<String> strings = new ArrayList<>();
for ( int j = 0; j < row.size(); j++) {
String value = row.getString(j);
strings.add(value);
}
excelList.add(strings);
}
return excelList;
}随后,构造XSSFWorkbook。创建XSSFWorkbook对象和XSSFSheet工作表对象,将上一步的数据源填充进XSSFWorkbook,代码如下:
public static XSSFWorkbook reportExcel(List<List<String>> excelList, String title) {
//创建excel工作簿
XSSFWorkbook workbook = new XSSFWorkbook();
//创建工作表sheet
XSSFSheet sheet = workbook.createSheet();
// 创建标题
XSSFRow headRow = sheet.createRow(0);
XSSFCell headCell = headRow.createCell(0);
// 设置标题的值
headCell.setCellValue(title);
// 合并第1行的前几列,合并列数 = excel的列数
CellRangeAddress titleCellAddresses = new CellRangeAddress(0, 0, 0, excelList.get(0).size()-1);
sheet.addMergedRegion(titleCellAddresses);
//写入单据列表数据
for (int i = 0; i < excelList.size(); i++) {
// i+1是因为前面第1行加了一个标题,单据列表数据是从Excel的第2行开始的,所以要+1
XSSFRow nrow = sheet.createRow(i + 1);
for (int u = 0; u < ex如何以二开的方式引出Excel并自定义样式
声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。



