网易首页 > 网易号 > 正文 申请入驻

基于Excel和Java自动化:发票生成器

0
分享至

对于销售人员,使用Excel创建发票是很常见的。但是该过程通常涉及许多容易出错的手动操作,例如输入数据,复制/粘贴等。如何实现一个可以将数据从数据库自动填充到发票Excel模板中,而无需再辛苦手动输入,从繁重的手动录入中解脱出来,并且避免认为错误这是每个人迫切的需求。虫虫一直奉行理念:真正的自动化是解决用户痛点问题,把繁重人工劳动释放出来。本文我们就介绍一个老外的利用Java编写自动化程序实现自动化发票生成器的案例,案例中创建了一个Web应用程序Invoice Builder,并利用Excel模版文件,Java和Keikai将这种手动发票录入过程转换为集成的自动化过程。

总体架构

下图显示了发票生成器应用程序的体系:

首先,导入一个源Excel文件,其中包含2个空表,客户表和产品表。业务员将从这两个表中选择客户和产品。

接着,根据数据库查询,将客户和产品数据填充到相应的表中。

最后,导入2个发票模板;它们是业务员在Excel中创建的。这些模板将在以后使用。

工作流程:选择客户和产品后,应用将通过将客户和产品数据与所选发票模板结合在一起来创建发票。

应用的动图示例如下:

MVC模式

Keikai也支持MVC模式,在本应用MVC模式,具体如下:

视图:用ZUL编写的XML文件。ZK将zul文件转换为UI组件并在浏览器中呈现。

控制器:扩展ZK的Java类,SelectorComposer用于监听View触发的事件并控制ZK UI组件。通过Spreadsheet和RangeAPI控制Keikai。

模型:本实例中是CustomerService,但是它也可以是任何其他的Java业务类,例如身份验证,数据查询等。

具体实现

构建界面UI

界面UI构建中在实际选择了zul,当然也可以选择纯Java(例如Swing)来构建UI。可以使用创建组件new Image(),通过将组件添加到Groupbox(容器)appendChild(),并使用来注册事件侦听器addEventListener()。使用这些API,可以在组框内的模板列表数组上动态创建模板预览图:

@Wire

private Groupbox templateBox;

private String[] templateFileNameList = {"invoice-template1.xlsx", "invoice-template2.xlsx"};

...

private void buildTemplatePreview() {

...

Arrays.stream(templateFileNameList).forEach(fileName -> {

...

Image preview = new Image(fileNameWithoutExt + "-preview.jpg");

templateBox.appendChild(preview);

preview.setAttribute(TEMPLATE_KEY, fileName);

preview.addEventListener(org.zkoss.zk.ui.event.Events.ON_CLICK, event ->

selectTemplate((Image) event.getTarget()));

...

});

...

}

由于业务人员往往习惯使用Excel模板,主程序界面采用了Keikai Spreadsheet,这样可以继续使用其现有模板。

Keikai基于ZK UI框架,该框架提供了完整的UI组件集以及XML格式的UI语言。

按照ZK的语法,使用XML标签中的以下UI组件构建此Web应用程序的UI:

maxVisibleRows="6" maxVisibleColumns="8"

src="/WEB-INF/books/invoice-source.xlsx"

showSheetbar="true"/>

:keikai电子表格。

:水平布置其子组件,垂直布置组件。

:带有边框和标题的组件分组。

每个标签都支持一些属性,例如:

src:指定要导入到Keikai的Excel文件路径。

maxVisibleRows:控制keikai在浏览器中渲染工作表时的最大可见行数。

控制器

要为页面指定控制器,只需在apply属性处指定了全限定的类名:

...

然后,该控制器可以控制其子组件。我通常在页面的根组件上指定一个控制器。

自动填充客户

现在可以显示电子表格和源文件,接着需要将数据自动填充到表。

源Excel文件仅包含一个空客户表,其表样式如列名和标题颜色。这里的一件好事是,这个Excel文件是由我的销售人员使用Excel创建的-他更清楚自己想在此表中看到的内容。

从服务类加载客户列表,并将列表填充到表中:

private void populateCustomers() {

List customers = CustomerService.getCustomerList();

Range startingCell = customerTable.toCellRange(0, 1); //the 1st column is for checkbox

for (String[] c : customers) {

RangeHelper.setValuesInRow(startingCell, c);

startingCell = startingCell.toShiftedRange(1, 0);

}

}

CustomerService 也可以是您所提供的数据实体的任何Java类。

setValuesInRow() 用字符串数组(例如B2,C2,D2 ...)一行一行地填充多个单元格

toShiftedRange(1, 0)转移startingCell到下一行。

用命名范围填充数据

将数据填充到电子表格UI时,需要指定要将数据填充到的目标单元格。选择命名范围是因为它是一种灵活的方法。

首先,创建几个指定范围中的每个模板文件例如Name,Phone和Email客户详细信息。最终用户选择客户和产品后,控制器将每一行提取为地图。索引是标题,该值是对应的单元格值,例如

然后,从所选模板中克隆发票表,并将客户详细信息填充到相应的命名范围中。

@Listen(org.zkoss.zk.ui.event.Events.ON_CLICK + "=#create")

public void createInvoice() {

...

Book invoiceBook = Books.createBook("invoice.xlsx");

for (Map customer : selectedCustomers) {

Sheet invoiceSheet = Ranges.range(invoiceBook).cloneSheetFrom(customer.get("CompanyName").toString()

, templates.get(getSelectedTemplateFileName()).getSheetAt(0));

populateNamedRange(generateAgentData(), invoiceSheet);

populateNamedRange(customer, invoiceSheet);

...

}

...

}

private void populateNamedRange(Map fieldMap, Sheet sheet) {

List namedRanges = Ranges.getNames(sheet);

fieldMap.forEach((name, value) -> {

if (namedRanges.contains(name)) {

Range range = Ranges.rangeByName(sheet, name);

range.setCellValue(value);

}

});

}

用户权限控制

在此应用程序中,客户数据是从数据库中填充的,不希望用户可以更改,只可以选择这些记录。因此,通过以下方式限制了它们在用户界面上可以执行的操作:

隐藏工具栏和上下文菜单:

通过指定使工作表标签可见showSheetbar="true"。默认情况下,其他所有内容(如工具栏,公式栏和上下文菜单)都是不可见的。这样,用户就不会无意间更改了UI上显示的内容。

启用工作表保护并禁用添加工作表

通过以下方式启用工作表保护:protectSheet()将所有工作表设为只读,并禁止用户通过添加工作表disableUserAction()。

private void limitAccess() {

for (int i = 0; i < spreadsheet.getBook().getNumberOfSheets(); i++) {

Ranges.range(spreadsheet.getBook().getSheetAt(i)).protectSheet(SELECTION_FILTER);

}

spreadsheet.disableUserAction(AuxAction.ADD_SHEET, true);

}

工作表保护下的可编辑区域

在Excel中,可以取消选中锁定状态以在工作表保护下使单元格可编辑。其他单元将保持只读状态。使用此设置,可以在受保护的图纸中允许一定范围的可编辑区域。导入到Keikai后,此设置将保留,因此可以在准备源文件时从Excel端完成。

重用

在应用程序中,有2个Excel模板,想一次导入它们,然后在需要时使用它们。

Keikai Importer将Excel xlsx文件转换为Book。可以将Book分配给Spreadsheet并将其呈现给浏览器。或者,可以直接操作Bookwith Range,而无需将其分配给Spreadsheet。最常见的用法是从模板书克隆表或复制单元格。每个需要Excel模板的人都可以从其中获取内容,而无需再次导入模板文件。在应用程序中,将Book2个模板Excel文件的对象存储在Map(templateWarehouse)中,以备将来使用:

private static HashMap templateWarehouse = new HashMap<>();

private static Importer importer = Importers.getImporter();

...

private void importInvoiceTemplate() {

...

for (String fileName : templateFileNameList) {

if (!templateWarehouse.containsKey(fileName)) { //avoid importing again

templateWarehouse.put(fileName

, importer.imports(new File(WebApps.getCurrent().getRealPath(BookUtil.DEFAULT_BOOK_FOLDER)

, fileName), fileName));

}

}

...

}

importer.imports(new File(...)) 返回一个Book。

总结

本文中我们演示了如何将现有的手动Excel文件的流程转换为具有Excel文件,Java和Keikai的Web应用程序。该应用程序与后端服务集成在一起,包括数据库和用户权限控制。可以将相同的技术应用于涉及基于Excel的流程的任何其他方案,将手动工作流转变为自动化和集成的Web Apps。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
新加坡女子赌神附体狂赢$1029万,破纪录! 网友:恐无法带回国...

新加坡女子赌神附体狂赢$1029万,破纪录! 网友:恐无法带回国...

新加坡万事通
2026-05-24 18:47:27
只差临门一脚!美伊协议曝光,以色列被踢出局

只差临门一脚!美伊协议曝光,以色列被踢出局

上游新闻
2026-05-24 22:12:11
暴雨黄色预警!江南江汉江淮黄淮等地警惕强降雨可能引发次生灾害

暴雨黄色预警!江南江汉江淮黄淮等地警惕强降雨可能引发次生灾害

环球网资讯
2026-05-24 08:56:09
兰州相亲现场:35+女士站成排,男士都绕着走,评论区全是大实话

兰州相亲现场:35+女士站成排,男士都绕着走,评论区全是大实话

谭谈社会
2026-05-24 23:20:37
国际乒联官员:樊振东被遮脸是中国区独立运营社媒 和乒联总部无关

国际乒联官员:樊振东被遮脸是中国区独立运营社媒 和乒联总部无关

818体育
2026-05-24 21:35:25
王鹤棣全网掉粉超20万!代言和作品遭抵制,路人缘崩塌难以挽回

王鹤棣全网掉粉超20万!代言和作品遭抵制,路人缘崩塌难以挽回

萌神木木
2026-05-24 11:50:12
涉嫌严重违纪违法,徐华强被查

涉嫌严重违纪违法,徐华强被查

都市快报橙柿互动
2026-05-24 17:48:13
亡国灭种,断子绝孙?欧洲反华先锋立陶宛,正在从地图上消失

亡国灭种,断子绝孙?欧洲反华先锋立陶宛,正在从地图上消失

贱议你读史
2026-05-23 12:07:35
港人瘋狂刷屏:香港好威,中國萬歲!

港人瘋狂刷屏:香港好威,中國萬歲!

新浪财经
2026-05-25 00:47:55
最佳阵容公布!詹库里字未入选!时代变了!

最佳阵容公布!詹库里字未入选!时代变了!

柚子说球
2026-05-25 08:06:55
每瓶仅含0.01克,喝几千瓶才抵一个桃!“饮料一哥”也翻车了?杭州多家超市在售,你可能也喝过

每瓶仅含0.01克,喝几千瓶才抵一个桃!“饮料一哥”也翻车了?杭州多家超市在售,你可能也喝过

都市快报橙柿互动
2026-05-24 20:48:16
高温连破历史记录,印度政府却将空调压缩机进口比例上限收紧至30%,加剧供需矛盾

高温连破历史记录,印度政府却将空调压缩机进口比例上限收紧至30%,加剧供需矛盾

风向观察
2026-05-24 16:33:31
教科书为何要删掉《卖油翁》最后一句话?最后一句到底有何深意?

教科书为何要删掉《卖油翁》最后一句话?最后一句到底有何深意?

心中的麦田
2026-05-23 19:43:10
7只半导体热门股集体宣布:股东减持!套现金额可达127亿元,有公司股价刚创新高

7只半导体热门股集体宣布:股东减持!套现金额可达127亿元,有公司股价刚创新高

每日经济新闻
2026-05-25 02:02:32
为何日本面积那么小,还能住下1.24亿人,且家家都是独栋?

为何日本面积那么小,还能住下1.24亿人,且家家都是独栋?

抽象派大师
2026-05-22 16:51:49
江苏常熟一仓库发生火灾,系隆力奇产品仓库,工作人员:火灾为晚间发生,未造成人员伤亡,经济损失暂无统计报告

江苏常熟一仓库发生火灾,系隆力奇产品仓库,工作人员:火灾为晚间发生,未造成人员伤亡,经济损失暂无统计报告

台州交通广播
2026-05-24 17:51:29
从“产品大年”到“心智沉淀”:金标大众的小满哲学

从“产品大年”到“心智沉淀”:金标大众的小满哲学

车厘子大叔
2026-05-24 15:22:36
女顾客投诉男人光膀子健身,老板直接禁止女性进入,评论区已吵翻

女顾客投诉男人光膀子健身,老板直接禁止女性进入,评论区已吵翻

谭谈社会
2026-05-24 17:53:33
周冬雨“拔萝卜”的瓜!

周冬雨“拔萝卜”的瓜!

八卦疯叔
2026-05-23 11:01:00
30位情妇、60辆豪车,有钱人的生活能有多奢淫?比赌王过得还潇洒

30位情妇、60辆豪车,有钱人的生活能有多奢淫?比赌王过得还潇洒

历史伟人录
2026-05-24 20:05:31
2026-05-25 08:36:49
文丽爱生活
文丽爱生活
生活多姿彩
2225文章数 1576关注度
往期回顾 全部

科技要闻

神舟二十三号航天员乘组顺利进驻“天宫”

头条要闻

暴雨突袭17岁少年赤膊上阵 让村民踩着他大腿肩膀转移

头条要闻

暴雨突袭17岁少年赤膊上阵 让村民踩着他大腿肩膀转移

体育要闻

唐斯发牌,大头逆袭:骑士跌向残忍夏季

娱乐要闻

王鹤棣掉粉超20万!代言和作品遭抵制

财经要闻

退市!33年“A股不死鸟”落幕

汽车要闻

国民家轿再上新 帝豪向上系列限时5.59万起

态度原创

旅游
教育
房产
游戏
公开课

旅游要闻

俄罗斯不容错过的新博物馆

教育要闻

在这个拼人脉的世界,会说话真的很重要!

房产要闻

疯狂周末,海口楼市突然爆了!

阿卡姆蝙蝠侠本质上就是披着斗篷的詹姆斯邦德

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版