找回密码
 立即注册

QQ登录

只需一步,快速开始

Clark.Pan 讲师达人认证 悬赏达人认证 SpreadJS 开发认证
超级版主   /  发表于:2021-8-27 19:35  /   查看:3817  /  回复:1
本帖最后由 Clark.Pan 于 2024-12-19 10:26 编辑

Hello,我有回来了,本期为大家带来SpreadJ+GcExcel 应对大量公式计算场景的解决方案的第二期(是的,你没看错,后面还有下),没有看过上的小伙伴请点击下方跳转先预习一下,以免看不懂。
SpreadJ+GcExcel 应对大量公式计算场景第一期

本期我们讲述一些核心的代码实现:

1、GcExcel后端读取整个xlsx文件,第一次读取由于Excel文件之前会自己重算,所以可以巧妙利用这一点在读取后关闭后端计算引擎,这样可以节省一次重计算的时间。读取文件的时候尽量用流进行读取,流的效率要比字符串高效很多。
  1. workbook.open(SpreadController.class.getClassLoader().getResourceAsStream("Excel/Wicked.xlsx"),options);
  2. workbook.setEnableCalculation(false);
复制代码
2、之后查询获取所有的Sheet工作表个数及名称及工作表显示隐藏的状态,这个后面有用
  1. List<Sheet> sheetNameList = new ArrayList<Sheet>();
  2. for(int i=0;i<workbook.getWorksheets().getCount();i++) {
  3.   Sheet sheet = new Sheet();
  4.   IWorksheet worksheet = workbook.getWorksheets().get(i);
  5.   sheet.setName(worksheet.getName());
  6.   if(Visibility.Hidden.equals(worksheet.getVisible())) {
  7.     sheet.setVisiable(false);
  8.   }else {
  9.     sheet.setVisiable(true);
  10.   }
  11.   sheetNameList.add(sheet);
  12. }
复制代码
3、获取activeSheet的名称和ssjson,将上述整个合并到结果中返回,这里可以将返回结果进行压缩,进一步返回大小,这样可有效加快网络请求的时间(事例中用了GZip的通用压缩工具)。
  1. IWorksheet activeSheet = workbook.getActiveSheet();
  2. String activeSheetName = activeSheet.getName();
  3. returnMap.put("activeSheetName", activeSheetName);

  4. String result = activeSheet.toJson();
  5. result = GZip.compress(result);
  6. returnMap.put("sheetJSON", result);
复制代码


4.前端SpreadJS接收到结果后,根据第二步工作表的名称及个数新建等量的工作表并改名改状态。这里完了之后可以将前端计算引擎挂起(本方案无需前端计算,但需要有前端的公式显示作为提示)。然后获取activeSheet并反序列化第三步生成的ssjson
  1. spread.setSheetCount(length);
  2. for(var i=0;i<length;i++){
  3.   spread.getSheet(i).name(data.sheetNames[i].name);
  4.   if(data.sheetNames[i].visiable == false){
  5.     spread.getSheet(i).visible(false);
  6.   }
  7.   if(data.sheetNames[i].name == data.activeSheetName){
  8.     spread.setActiveSheetIndex(i);
  9.   }
  10. }
  11. spread.suspendCalcService(false);
  12. var activeSheet = spread.getActiveSheet();
  13. var json = data.sheetJSON;
  14. json = ungzipString(json);
  15. json = JSON.parse(json);
  16. activeSheet.fromJSON(json);
复制代码


这样初步加载就完成了,还没有睡着的小伙伴可以继续接着向下看。


4. 根据刚刚的设计,前端SpreadJS中,目前只有activeSheet是有货的,其余都是空的sheet。这个时候我们就需要去监听事件,通过事件驱动来进行缓式加载。这里监听了ActiveSheetChanging事件,用于在sheet切换的时机去后端获取新的activeSheet的ssjson。这里以防用户在sheet上进行修改,同时获取了脏数据,一并传给后端。最终将后端的返回结果在前端反序列化。
  1. spread.bind(GC.Spread.Sheets.Events.ActiveSheetChanging, function (sender, args) {
  2.                 var oldSheet = args.oldSheet;
  3.                 var dirtyCells = oldSheet.getDirtyCells();
  4.                 var newSheet = args.newSheet;
  5.                 var sheetChange = {
  6.   oldSheetName:oldSheet.name(),
  7.   newSheetName:newSheet.name(),
  8.   dirtyCells:dirtyCells        
  9.                 }
  10.                 $.ajax({
  11.   url: "getSheet",
  12.   type:"POST",
  13.   data:JSON.stringify(sheetChange),
  14.   contentType: 'application/json',
  15.   async:false,
  16.   success: function (data) {
  17.     if (data != null) {
  18.       var json = ungzipString(data);
  19.       json = JSON.parse(json);
  20.       newSheet.fromJSON(json);
  21.     }
  22.   }
  23.                     });
  24.             });
复制代码
5.后端拿到上述信息同步到整体的workbook中,然后重新计算得到计算后的结果,在将新的activeSheet序列化成ssjson返回
  1. IWorksheet oldSheet = workbook.getWorksheets().get(sheetChange.getOldSheetName());
  2.                 if(sheetChange.getDirtyCells().size()>0) {
  3.   for(int i=0;i<sheetChange.getDirtyCells().size();i++) {
  4.     Map<String,Object> dirtyCell = sheetChange.getDirtyCells().get(i);
  5.     int row = (int) dirtyCell.get("row");
  6.     int col = (int) dirtyCell.get("col");
  7.     oldSheet.getRange(row, col).setValue(dirtyCell.get("newValue"));
  8.   }
  9.   workbook.setEnableCalculation(true);
  10.                 }
  11.                
  12.                 IWorksheet newSheet = workbook.getWorksheets().get(sheetChange.getNewSheetName());
  13.                 String result = null;
  14.                 if(newSheet!=null) {
  15.   result = newSheet.toJson();
  16.   result = GZip.compress(result);        
  17.                 }
  18.                 return result;
复制代码


这样,大致的思路已经讲完了。有没有恍然大悟的感觉呢?


那么本期的内容的也先告一段落了,下一期我们谈一谈该方案的功能扩展以及性能的对比测试,提前预告下一期会有神秘惊喜哦。


image.png200489195.png
image.png62418517.png
image.png28248290.png
您需要登录后才可以回帖 登录 | 立即注册
返回顶部