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

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

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

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

基于Excel和Java自动化工作流程发票生成器示例

运用的动图示例如下:

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,可以在组框内的模板列表数组上动态创建模板预览图:

@Wireprivate 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:

<hlayout vflex="1" width="100%" apply="io.keikai.devref.usecase.invoice.InvoiceBuilderController"><spreadsheet height="100%" id="spreadsheet" hflex="8"maxVisibleRows="6" maxVisibleColumns="8"src="/WEB-INF/books/invoice-source.xlsx"showSheetbar="true"/><vlayout hflex="2" height="100%"><groupbox id="templateBox" title="Template" style="text-align: center"></groupbox><button id="create" label="Create" style="float: right"/></vlayout></hlayout>

<spreadsheet>:keikai电子表格。

<hlayout>:水平支配其子组件,<vlayout>垂直支配组件。

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

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

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

maxVisibleRows:掌握keikai在浏览器中渲染事情表时的最大可见行数。

掌握器

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

<hlayout vflex="1" width="100%" apply="io.keikai.devref.usecase.invoice.InvoiceBuilderController">...</hlayout>

然后,该掌握器可以掌握<hlayout>其子组件。
我常日在页面的根组件上指定一个掌握器。

自动添补客户

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

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

从做事类加载客户列表,并将列表添补到表中:

private void populateCustomers() {List<String[]> customers = CustomerService.getCustomerList();Range startingCell = customerTable.toCellRange(0, 1); //the 1st column is for checkboxfor (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客户详细信息。
终极用户选择客户和产品后,掌握器将每一行提取为舆图。
索引是标题,该值是对应的单元格值,例如

{Name: Debra, Phone: 338-8777, Email: debra@...}。

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

@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<String, Object> fieldMap, Sheet sheet) {List<String> namedRanges = Ranges.getNames(sheet);fieldMap.forEach((name, value) -> {if (namedRanges.contains(name)) {Range range = Ranges.rangeByName(sheet, name);range.setCellValue(value);}});}用户权限掌握

在此运用程序中,客户数据是从数据库中添补的,不肯望用户可以变动,只可以选择这些记录。
因此,通过以下办法限定了它们在用户界面上可以实行的操作:

隐蔽工具栏和高下文菜单:

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

<spreadsheet ... showSheetbar="true"/>

启用事情表保护并禁用添加事情表

通过以下办法启用事情表保护: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<String, Book> templateWarehouse = new HashMap<>();private static Importer importer = Importers.getImporter();...private void importInvoiceTemplate() {...for (String fileName : templateFileNameList) {if (!templateWarehouse.containsKey(fileName)) { //avoid importing againtemplateWarehouse.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。