本帖最后由 Clark.Pan 于 2024-12-19 10:26 编辑
Hello,我有回来了,本期为大家带来SpreadJ+GcExcel 应对大量公式计算场景的解决方案的第二期(是的,你没看错,后面还有下),没有看过上的小伙伴请点击下方跳转先预习一下,以免看不懂。
SpreadJ+GcExcel 应对大量公式计算场景第一期
本期我们讲述一些核心的代码实现:
1、GcExcel后端读取整个xlsx文件,第一次读取由于Excel文件之前会自己重算,所以可以巧妙利用这一点在读取后关闭后端计算引擎,这样可以节省一次重计算的时间。读取文件的时候尽量用流进行读取,流的效率要比字符串高效很多。
- workbook.open(SpreadController.class.getClassLoader().getResourceAsStream("Excel/Wicked.xlsx"),options);
- workbook.setEnableCalculation(false);
复制代码 2、之后查询获取所有的Sheet工作表个数及名称及工作表显示隐藏的状态,这个后面有用
- List<Sheet> sheetNameList = new ArrayList<Sheet>();
- for(int i=0;i<workbook.getWorksheets().getCount();i++) {
- Sheet sheet = new Sheet();
- IWorksheet worksheet = workbook.getWorksheets().get(i);
- sheet.setName(worksheet.getName());
- if(Visibility.Hidden.equals(worksheet.getVisible())) {
- sheet.setVisiable(false);
- }else {
- sheet.setVisiable(true);
- }
- sheetNameList.add(sheet);
- }
复制代码 3、获取activeSheet的名称和ssjson,将上述整个合并到结果中返回,这里可以将返回结果进行压缩,进一步返回大小,这样可有效加快网络请求的时间(事例中用了GZip的通用压缩工具)。
- IWorksheet activeSheet = workbook.getActiveSheet();
- String activeSheetName = activeSheet.getName();
- returnMap.put("activeSheetName", activeSheetName);
- String result = activeSheet.toJson();
- result = GZip.compress(result);
- returnMap.put("sheetJSON", result);
复制代码
4.前端SpreadJS接收到结果后,根据第二步工作表的名称及个数新建等量的工作表并改名改状态。这里完了之后可以将前端计算引擎挂起(本方案无需前端计算,但需要有前端的公式显示作为提示)。然后获取activeSheet并反序列化第三步生成的ssjson
- spread.setSheetCount(length);
- for(var i=0;i<length;i++){
- spread.getSheet(i).name(data.sheetNames[i].name);
- if(data.sheetNames[i].visiable == false){
- spread.getSheet(i).visible(false);
- }
- if(data.sheetNames[i].name == data.activeSheetName){
- spread.setActiveSheetIndex(i);
- }
- }
- spread.suspendCalcService(false);
- var activeSheet = spread.getActiveSheet();
- var json = data.sheetJSON;
- json = ungzipString(json);
- json = JSON.parse(json);
- activeSheet.fromJSON(json);
复制代码
这样初步加载就完成了,还没有睡着的小伙伴可以继续接着向下看。
4. 根据刚刚的设计,前端SpreadJS中,目前只有activeSheet是有货的,其余都是空的sheet。这个时候我们就需要去监听事件,通过事件驱动来进行缓式加载。这里监听了ActiveSheetChanging事件,用于在sheet切换的时机去后端获取新的activeSheet的ssjson。这里以防用户在sheet上进行修改,同时获取了脏数据,一并传给后端。最终将后端的返回结果在前端反序列化。
- spread.bind(GC.Spread.Sheets.Events.ActiveSheetChanging, function (sender, args) {
- var oldSheet = args.oldSheet;
- var dirtyCells = oldSheet.getDirtyCells();
- var newSheet = args.newSheet;
- var sheetChange = {
- oldSheetName:oldSheet.name(),
- newSheetName:newSheet.name(),
- dirtyCells:dirtyCells
- }
- $.ajax({
- url: "getSheet",
- type:"POST",
- data:JSON.stringify(sheetChange),
- contentType: 'application/json',
- async:false,
- success: function (data) {
- if (data != null) {
- var json = ungzipString(data);
- json = JSON.parse(json);
- newSheet.fromJSON(json);
- }
- }
- });
- });
复制代码 5.后端拿到上述信息同步到整体的workbook中,然后重新计算得到计算后的结果,在将新的activeSheet序列化成ssjson返回
- IWorksheet oldSheet = workbook.getWorksheets().get(sheetChange.getOldSheetName());
- if(sheetChange.getDirtyCells().size()>0) {
- for(int i=0;i<sheetChange.getDirtyCells().size();i++) {
- Map<String,Object> dirtyCell = sheetChange.getDirtyCells().get(i);
- int row = (int) dirtyCell.get("row");
- int col = (int) dirtyCell.get("col");
- oldSheet.getRange(row, col).setValue(dirtyCell.get("newValue"));
- }
- workbook.setEnableCalculation(true);
- }
-
- IWorksheet newSheet = workbook.getWorksheets().get(sheetChange.getNewSheetName());
- String result = null;
- if(newSheet!=null) {
- result = newSheet.toJson();
- result = GZip.compress(result);
- }
- return result;
复制代码
这样,大致的思路已经讲完了。有没有恍然大悟的感觉呢?
那么本期的内容的也先告一段落了,下一期我们谈一谈该方案的功能扩展以及性能的对比测试,提前预告下一期会有神秘惊喜哦。
|
|