还在担心报表不好做?不用怕,试试这个方法

前言

在各种业务场景中,我们经常需要生成各种报表,例如学校中的学生成绩表、商业场景中的销售单和发票单、测量检测场景中的检测报告等等。这些报表对于组织和管理数据非常重要,因为它们提供了直观、清晰的方式来展示和分析数据。

一般情况下,使用Excel设计和生成这些报表就可以,但是随着业务规模的扩大,需求也会逐渐由人工转变为电脑自动批量生成,这个时候再用Excel设计就非常慢了,因此今天小编为大家介绍一下如何使用编程语言来设计一个报表。

操作步骤

下图是一个简单的学生成绩表,以下表为例给大家介绍一下操作的具体步骤:

  1. 抽象数据结构

首先按照报表中的字段(学号、姓名等)抽象对应的数据结构:

Java 复制代码
class Data {
    public String School;
    public int Grade;
    public int Class;
    public String PrintDate;
    public ArrayList<Score> Scores = new ArrayList<>();
}

class Score {
    public int SID;
    public String SName;
    public int Chinese;
    public int Math;
    public int English;

    public Score(int sid, String sName, int chinese, int math, int english) {
        this.SID = sid;
        this.SName = sName;
        this.Chinese = chinese;
        this.Math = math;
        this.English = english;
    }
}
  1. 传数据

第二步小编将数据传入到第一步生成数据结构的Scores 队列中。

Java 复制代码
private static Data CreateData() {
    Data data = new Data();
    data.School = "高新第六小学";
    data.Grade = 1;
    data.Class = 2;
    data.PrintDate = "2023年1月5日";

    data.Scores.add(new Score(1, "李明", 98, 100, 96));
    data.Scores.add(new Score(2, "王芳", 96, 97, 98));
    data.Scores.add(new Score(3, "张锋", 99, 99, 95));
    data.Scores.add(new Score(4, "高明", 94, 96, 100));
    data.Scores.add(new Score(5, "沈梦", 90, 94, 93));
    data.Scores.add(new Score(6, "张菲", 93, 94, 95));
    data.Scores.add(new Score(7, "白洁", 95, 92, 94));
    data.Scores.add(new Score(8, "王鹏", 96, 97, 99));
    data.Scores.add(new Score(9, "刘玲", 96, 93, 94));
    data.Scores.add(new Score(10, "李丽", 94, 98, 99));
    return data;
}
  1. 生成报表逻辑

生成数据之后,下面是编写生成一个报表的代码,该代码创建了一个工作簿并添加了一个工作表。除了添加数据外,还配置了报表所需的样式。

可以看到,该代码量不小且与业务高度相关。如果报表的样式或布局发生变化,就需要调整代码,这种情况下,维护成本会很高。

Java 复制代码
Data data = CreateData();

Workbook workbook = new Workbook();
IWorksheet worksheet = workbook.getWorksheets().get(0);

worksheet.getRange("A1").setValue(data.School);
worksheet.getRange("A3").setValue("年级");
worksheet.getRange("B3").setValue(data.Grade);
worksheet.getRange("D3").setValue("班级");
worksheet.getRange("E3").setValue(data.Class);

Object[] array = new Object[]{"学号", "姓名", "语文", "数学", "英语"};
worksheet.getRange("A5:E5").setValue(array);

worksheet.getRange("D7").setValue("打印日期");
worksheet.getRange("E7").setValue("2023年1月5日");

//报表样式
worksheet.getRange("A1:E1").setColumnWidthInPixel(140);
worksheet.getRange("1:2").setRowHeightInPixel(50);

worksheet.getRange("A1:E1").merge();
worksheet.getRange("A1").getFont().setSize(16);
worksheet.getRange("A1").setHorizontalAlignment(HorizontalAlignment.Center);

worksheet.getRange("B3,E3").getBorders().get(BordersIndex.EdgeBottom).setColor(Color.GetBlack());
worksheet.getRange("A3:E3,D7").setHorizontalAlignment(HorizontalAlignment.Center);

worksheet.getRange("E7").setHorizontalAlignment(HorizontalAlignment.Right);


int baseRow = 5;
int dataRowCount = data.Scores.size();
worksheet.getRange(5, 0, dataRowCount, 1).getEntireRow().insert(InsertShiftDirection.Down);
for (int i = 0; i < data.Scores.size(); i++) {
    worksheet.getRange(baseRow + i, 0).setValue(data.Scores.get(i).SName);
    worksheet.getRange(baseRow + i, 1).setValue(data.Scores.get(i).SID);
    worksheet.getRange(baseRow + i, 2).setValue(data.Scores.get(i).Chinese);
    worksheet.getRange(baseRow + i, 3).setValue(data.Scores.get(i).Math);
    worksheet.getRange(baseRow + i, 4).setValue(data.Scores.get(i).English);
}

worksheet.getRange("A5:E5").getInterior().setColor(Color.FromArgb(21, 96, 130));
worksheet.getRange("A5:E5").getFont().setColor(Color.GetWhite());
worksheet.getRange("A5:E5").setHorizontalAlignment(HorizontalAlignment.Center);

worksheet.getRange(baseRow, 0, dataRowCount, 5).getInterior().setColor(Color.FromArgb(192, 230, 245));
worksheet.getRange(baseRow - 1, 0, dataRowCount + 1, 5).getBorders().setColor(Color.FromArgb(68, 179, 225));
worksheet.getRange(baseRow - 1, 0, dataRowCount + 1, 2).setHorizontalAlignment(HorizontalAlignment.Center);

worksheet.getSheetView().setDisplayGridlines(false);
  1. 通过模板简化生成报表逻辑代码

通过第三步的代码可以发现,许多样式,如字体、列宽、行高和颜色等都是相同的,但数据和布局却与业务密切相关,并随着报表而变化。为了解决上述问题,可以将报表抽象为一个Excel模板,并保留不变的内容,移除可变的内容,如下图所示:

这样小编就可以简化报表样式部分的代码,保留核心代码,如下所示:

Java 复制代码
Data data = CreateData();

Workbook workbook = new Workbook();
workbook.open("template.xlsx");
IWorksheet worksheet = workbook.getWorksheets().get(0);

worksheet.getRange("A1").setValue(data.School);
worksheet.getRange("B3").setValue(data.Grade);
worksheet.getRange("E3").setValue(data.Class);
worksheet.getRange("E8").setValue("2023年1月5日");

int baseRow = 5;
int dataRowCount = data.Scores.size();
worksheet.getRange(baseRow + 1, 0, dataRowCount - 1, 1).getEntireRow().insert(InsertShiftDirection.Down);
worksheet.getRange(baseRow, 0, 1, 5).copy(worksheet.getRange(baseRow + 1, 0, dataRowCount - 1, 5));
//循环给报表中的字段传值
for (int i = 0; i < data.Scores.size(); i++) {
    worksheet.getRange(baseRow + i, 0).setValue(data.Scores.get(i).SName);
    worksheet.getRange(baseRow + i, 1).setValue(data.Scores.get(i).SID);
    worksheet.getRange(baseRow + i, 2).setValue(data.Scores.get(i).Chinese);
    worksheet.getRange(baseRow + i, 3).setValue(data.Scores.get(i).Math);
    worksheet.getRange(baseRow + i, 4).setValue(data.Scores.get(i).English);
}

可以看到,剥离掉样式的代码,简化了很多。但是,布局的调整,尤其是需要根据数据量调整行列,还是没有做到完全的业务解耦。

  1. 使用模板语言二次简化代码

为了进一步解决第四步中的问题,我们可以通过模板语言,将报表改造成模板文件,来彻底做到业务解耦。将业务需求留在模板文件中,大大降低了代码维护的成本。下面小编对第四步的模板进行一些改造,如下图所示:

可以看到,和第四步的模板相比,新的模板将字段(年龄、班级等)对应的值以参数值表示,以{{ds.School}}为例,模板语言由两个大括号组成,中间的字符串表示从名为ds的数据源中,将School字段填充至 C1 单元格中。

下面是使用报表语言后简化后的代码:

Java 复制代码
Workbook workbook = new Workbook();
workbook.open("template.xlsx");
workbook.addDataSource("ds",CreateData());
workbook.processTemplate();
workbook.save("reprot.xlsx");

展示效果:

总结

本文所用到的所有代码均来自葡萄城公司的服务端表格控件产品GcExcel。如果您想了解更多信息,可以参考这篇产品文档Demo 网站

扩展链接:

Redis从入门到实践

一节课带你搞懂数据库事务!

Chrome开发者工具使用教程

如何在Web应用中添加一个JavaScript Excel查看器

高性能渲染------详解HTML Canvas的优势与性能

相关推荐
七星静香8 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员9 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU9 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie612 分钟前
在IDEA中使用Git
java·git
Elaine20239128 分钟前
06 网络编程基础
java·网络
G丶AEOM29 分钟前
分布式——BASE理论
java·分布式·八股
落落鱼201330 分钟前
tp接口 入口文件 500 错误原因
java·开发语言
想要打 Acm 的小周同学呀31 分钟前
LRU缓存算法
java·算法·缓存
镰刀出海34 分钟前
Recyclerview缓存原理
java·开发语言·缓存·recyclerview·android面试
阿伟*rui3 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel