dump java崩溃自动 不生成_基于Excel和Java自动化工作流程:发票生成器示例
對(duì)于銷售人員,使用Excel創(chuàng)建發(fā)票是很常見(jiàn)的。但是該過(guò)程通常涉及許多容易出錯(cuò)的手動(dòng)操作,例如輸入數(shù)據(jù),復(fù)制/粘貼等。如何實(shí)現(xiàn)一個(gè)可以將數(shù)據(jù)從數(shù)據(jù)庫(kù)自動(dòng)填充到發(fā)票Excel模板中,而無(wú)需再辛苦手動(dòng)輸入,從繁重的手動(dòng)錄入中解脫出來(lái),并且避免認(rèn)為錯(cuò)誤這是每個(gè)人迫切的需求。蟲(chóng)蟲(chóng)一直奉行理念:真正的自動(dòng)化是解決用戶痛點(diǎn)問(wèn)題,把繁重人工勞動(dòng)釋放出來(lái)。本文我們就介紹一個(gè)老外的利用Java編寫(xiě)自動(dòng)化程序?qū)崿F(xiàn)自動(dòng)化發(fā)票生成器的案例,案例中創(chuàng)建了一個(gè)Web應(yīng)用程序Invoice Builder,并利用Excel模版文件,Java和Keikai將這種手動(dòng)發(fā)票錄入過(guò)程轉(zhuǎn)換為集成的自動(dòng)化過(guò)程。
總體架構(gòu)
體系圖
下圖顯示了發(fā)票生成器應(yīng)用程序的體系圖:
首先,導(dǎo)入一個(gè)源Excel文件,其中包含2個(gè)空表,客戶表和產(chǎn)品表。業(yè)務(wù)員將從這兩個(gè)表中選擇客戶和產(chǎn)品。
接著,根據(jù)數(shù)據(jù)庫(kù)查詢,將客戶和產(chǎn)品數(shù)據(jù)填充到相應(yīng)的表中。
最后,導(dǎo)入2個(gè)發(fā)票模板;它們是業(yè)務(wù)員在Excel中創(chuàng)建的。這些模板將在以后使用。
工作流程:選擇客戶和產(chǎn)品后,應(yīng)用將通過(guò)將客戶和產(chǎn)品數(shù)據(jù)與所選發(fā)票模板結(jié)合在一起來(lái)創(chuàng)建發(fā)票。
應(yīng)用的動(dòng)圖示例如下:
MVC模式
Keikai也支持MVC模式,在本應(yīng)用MVC模式,具體如下:
視圖:用ZUL編寫(xiě)的XML文件。ZK將zul文件轉(zhuǎn)換為UI組件并在瀏覽器中呈現(xiàn)。
控制器:擴(kuò)展ZK的Java類,SelectorComposer用于監(jiān)聽(tīng)View觸發(fā)的事件并控制ZK UI組件。通過(guò)Spreadsheet和RangeAPI控制Keikai。
模型:本實(shí)例中是CustomerService,但是它也可以是任何其他的Java業(yè)務(wù)類,例如身份驗(yàn)證,數(shù)據(jù)查詢等。
具體實(shí)現(xiàn)
構(gòu)建界面UI
界面UI構(gòu)建中在實(shí)際選擇了zul,當(dāng)然也可以選擇純Java(例如Swing)來(lái)構(gòu)建UI。可以使用創(chuàng)建組件new Image(),通過(guò)將組件添加到Groupbox(容器)appendChild(),并使用來(lái)注冊(cè)事件偵聽(tīng)器addEventListener()。使用這些API,可以在組框內(nèi)的模板列表數(shù)組上動(dòng)態(tài)創(chuàng)建模板預(yù)覽圖:
@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()));...});...}由于業(yè)務(wù)人員往往習(xí)慣使用Excel模板,主程序界面采用了Keikai Spreadsheet,這樣可以繼續(xù)使用其現(xiàn)有模板。
Keikai基于ZK UI框架,該框架提供了完整的UI組件集以及XML格式的UI語(yǔ)言。
按照Z(yǔ)K的語(yǔ)法,使用XML標(biāo)簽中的以下UI組件構(gòu)建此Web應(yīng)用程序的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>:keikai電子表格。
:水平布置其子組件,垂直布置組件。
:帶有邊框和標(biāo)題的組件分組。
每個(gè)標(biāo)簽都支持一些屬性,例如:
src:指定要導(dǎo)入到Keikai的Excel文件路徑。
maxVisibleRows:控制keikai在瀏覽器中渲染工作表時(shí)的最大可見(jiàn)行數(shù)。
控制器
要為頁(yè)面指定控制器,只需在apply屬性處指定了全限定的類名:
<hlayout vflex="1" width="100%" apply="io.keikai.devref.usecase.invoice.InvoiceBuilderController">...hlayout>然后,該控制器可以控制其子組件。我通常在頁(yè)面的根組件上指定一個(gè)控制器。
自動(dòng)填充客戶
現(xiàn)在可以顯示電子表格和源文件,接著需要將數(shù)據(jù)自動(dòng)填充到表。
源Excel文件僅包含一個(gè)空客戶表,其表樣式如列名和標(biāo)題顏色。這里的一件好事是,這個(gè)Excel文件是由我的銷售人員使用Excel創(chuàng)建的-他更清楚自己想在此表中看到的內(nèi)容。
從服務(wù)類加載客戶列表,并將列表填充到表中:
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 也可以是您所提供的數(shù)據(jù)實(shí)體的任何Java類。
setValuesInRow() 用字符串?dāng)?shù)組(例如B2,C2,D2 ...)一行一行地填充多個(gè)單元格
toShiftedRange(1, 0)轉(zhuǎn)移startingCell到下一行。
用命名范圍填充數(shù)據(jù)
將數(shù)據(jù)填充到電子表格UI時(shí),需要指定要將數(shù)據(jù)填充到的目標(biāo)單元格。選擇命名范圍是因?yàn)樗且环N靈活的方法。
首先,創(chuàng)建幾個(gè)指定范圍中的每個(gè)模板文件例如Name,Phone和Email客戶詳細(xì)信息。最終用戶選擇客戶和產(chǎn)品后,控制器將每一行提取為地圖。索引是標(biāo)題,該值是對(duì)應(yīng)的單元格值,例如
{Name: Debra, Phone: 338-8777, Email: debra@...}。然后,從所選模板中克隆發(fā)票表,并將客戶詳細(xì)信息填充到相應(yīng)的命名范圍中。
@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);}});}用戶權(quán)限控制
在此應(yīng)用程序中,客戶數(shù)據(jù)是從數(shù)據(jù)庫(kù)中填充的,不希望用戶可以更改,只可以選擇這些記錄。因此,通過(guò)以下方式限制了它們?cè)谟脩艚缑嫔峡梢詧?zhí)行的操作:
隱藏工具欄和上下文菜單:
通過(guò)指定使工作表標(biāo)簽可見(jiàn)showSheetbar="true"。默認(rèn)情況下,其他所有內(nèi)容(如工具欄,公式欄和上下文菜單)都是不可見(jiàn)的。這樣,用戶就不會(huì)無(wú)意間更改了UI上顯示的內(nèi)容。
<spreadsheet ... showSheetbar="true"/>啟用工作表保護(hù)并禁用添加工作表
通過(guò)以下方式啟用工作表保護(hù):protectSheet()將所有工作表設(shè)為只讀,并禁止用戶通過(guò)添加工作表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);}工作表保護(hù)下的可編輯區(qū)域
在Excel中,可以取消選中鎖定狀態(tài)以在工作表保護(hù)下使單元格可編輯。其他單元將保持只讀狀態(tài)。使用此設(shè)置,可以在受保護(hù)的圖紙中允許一定范圍的可編輯區(qū)域。導(dǎo)入到Keikai后,此設(shè)置將保留,因此可以在準(zhǔn)備源文件時(shí)從Excel端完成。
重用
在應(yīng)用程序中,有2個(gè)Excel模板,想一次導(dǎo)入它們,然后在需要時(shí)使用它們。
Keikai Importer將Excel xlsx文件轉(zhuǎn)換為Book??梢詫ook分配給Spreadsheet并將其呈現(xiàn)給瀏覽器?;蛘?#xff0c;可以直接操作Bookwith Range,而無(wú)需將其分配給Spreadsheet。最常見(jiàn)的用法是從模板書(shū)克隆表或復(fù)制單元格。每個(gè)需要Excel模板的人都可以從其中獲取內(nèi)容,而無(wú)需再次導(dǎo)入模板文件。在應(yīng)用程序中,將Book2個(gè)模板Excel文件的對(duì)象存儲(chǔ)在Map(templateWarehouse)中,以備將來(lái)使用:
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(...)) 返回一個(gè)Book。
總結(jié)
本文中我們演示了如何將現(xiàn)有的手動(dòng)Excel文件的流程轉(zhuǎn)換為具有Excel文件,Java和Keikai的Web應(yīng)用程序。該應(yīng)用程序與后端服務(wù)集成在一起,包括數(shù)據(jù)庫(kù)和用戶權(quán)限控制。可以將相同的技術(shù)應(yīng)用于涉及基于Excel的流程的任何其他方案,將手動(dòng)工作流轉(zhuǎn)變?yōu)樽詣?dòng)化和集成的Web Apps。
總結(jié)
以上是生活随笔為你收集整理的dump java崩溃自动 不生成_基于Excel和Java自动化工作流程:发票生成器示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Effective C++: 06继承与
- 下一篇: 中service层的作用_浅析Java中