找回密码
 立即注册

QQ登录

只需一步,快速开始

Richard.Huang SpreadJS 开发认证

超级版主

43

主题

3197

帖子

4954

积分

超级版主

Rank: 8Rank: 8

积分
4954

SpreadJS 认证SpreadJS 高级认证

Richard.Huang SpreadJS 开发认证
超级版主   /  发表于:2023-9-21 14:22  /   查看:2514  /  回复:0
本帖最后由 Richard.Huang 于 2023-9-21 15:02 编辑

背景:
SpreadJS作为一款纯前端的表格控件,并不具备服务端的存储能力,因此想要持久化编辑的文件,大家只能保存在本地,这对于很多办公需求苛刻的用户来说并不是很好,用户更希望的是,将表格内容保存在云端,需要的时候,打开页面直接加载云端内容即可,我们怎么实现这个想法呢?
其实实现这个的方式有很多,例如之前大家阅读很多的通过数据流进行前后端传输的精华帖:SpreadJS + Vue + Axios 实现服务端加载、上传Excel,博主在帖子中提及的方案便是通过Excel文件的数据流来实现前后端的交互,数据流的方式不用落盘直接传输给后端保存,十分友好,但是Excel文件本身体积庞大,如果数据量也庞大,那么传输过程会因此变得缓慢。有没有更轻量的方式呢?答案是有的,SpreadJS在V16.2.2版本中提供了另一种新的.sjs的文件格式,该格式大大改善了非常大的Excel文件加载时间和内存使用SpreadJS自有文件格式,同时与以前的SpreadJS版本相比,重新保存后的文件大小大大减少

方法:
SpreadJS提供了open方法save方法对.sjs文件进行加载和保存,如果我们在文件落盘时拿到数据流,直接传输给后端,便不需要在前端进行落盘处理了,拿到数据流后直接传输给后端即可
  • 保存时拿取数据流传输给后端

  1. spread.save(
  2.        function (blob) {
  3.                 var xhr = new XMLHttpRequest();
  4.                 xhr.open("POST", "/sjs/add", true);

  5.                 var formData = new FormData();
  6.                 formData.append('sjs', blob);
  7.                 formData.append('fileName', inputValue);

  8.                 xhr.onreadystatechange = function () {
  9.                         if (xhr.readyState === XMLHttpRequest.DONE) {
  10.                                 if (xhr.status === 200) {
  11.                                         console.log(xhr.responseText);
  12.                                         var result = JSON.parse(xhr.responseText);
  13.                                         var code = result.code;

  14.                                         if (code === 200) {
  15.                                                 console.log("保存成功")
  16.                                         }
  17.                                 } else {
  18.                                         console.log(xhr.status);
  19.                                         console.log(xhr.responseText);
  20.                                 }
  21.                         }
  22.                 };

  23.                 xhr.send(formData);
  24.         },
  25.         function (e) {
  26.                 console.log(e);
  27.         }
  28. );
复制代码
  • 加载时请求数据流进行加载

  1. var spread = GC.Spread.Sheets.findControl(document.getElementById("ss"));
  2. xhr.open("get", "/sjs/get?fileName=" + inputValue)
  3. xhr.responseType = "blob"
  4. xhr.addEventListener("loadend", function () {
  5.         if (this.readyState == 4 && this.status == 200) {
  6.                 let file = new File([this.response], 'test.sjs')
  7.                 // 也可以封装成blob,spread.open()中直接传递blob即可
  8.                 // var blob = new Blob([this.response], {type:'application/zip'});
  9.                 spread.open(file)
  10.         }
  11. })
  12. xhr.send()
复制代码

后端可以使用我们的GCExcel对数据进行落盘,具体是用时可以将落盘的路径保存在关系型数据库中,例如mysql中,路径保存我们不做介绍,我们将核心的落盘的controller层方法进行实践:
1. 接收数据流并落盘
  1. @PostMapping("/add")
  2. public R addSJS(@RequestParam("sjs") MultipartFile sjsFile, @RequestParam("fileName") String fileName) throws IOException {
  3.         int userId = 4;
  4.         // 获取数据
  5.         String filePath = "data/" + userId + "/";
  6.         File directory = new File(filePath);
  7.         if (!directory.exists()) {
  8.                 boolean success = directory.mkdirs();
  9.                 if (success) {
  10.                         System.out.println("文件夹创建成功!");
  11.                 } else {
  12.                         System.out.println("文件夹创建失败!");
  13.                 }
  14.         } else {
  15.                 System.out.println("文件夹已存在!");
  16.         }

  17.         // 创建一个新的文件流来保存文件。
  18.         InputStream out = null;
  19.         try {
  20.                 out = sjsFile.getInputStream();
  21.         } catch (FileNotFoundException e) {
  22.             // 处理文件未找到异常。
  23.                 e.printStackTrace();
  24.         } catch (IOException e) {
  25.                 throw new RuntimeException(e);
  26.         }

  27.         // 保存流文件
  28.         Workbook workbook = new Workbook();
  29.         // 将Workbook对象保存为.sjs文件。
  30.         workbook.open(out, OpenFileFormat.Sjs);
  31.         workbook.save(filePath + fileName, SaveFileFormat.Sjs);
  32.         // 一切正常
  33.         return R.success(CodeEnum.SUCCESS,Constants.OK);
  34. }
复制代码
2. 获取文件,并加载为数据流进行传输
  1. @RequestMapping(value = "/get", method = RequestMethod.GET)
  2. public void downloadFile(@RequestParam("fileName") String fileName, HttpServletResponse response) throws IOException {
  3.         String ssjsonPath = "data/4/" + fileName;
  4.         File file = new File(ssjsonPath);

  5.     // 设置响应内容类型为二进制流
  6.         response.setContentType("application/octet-stream");
  7.         response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
  8.         response.setHeader("Content-Length", String.valueOf(file.length()));

  9.     // 读取文件并写入响应的输出流
  10.         InputStream inputStream = new FileInputStream(file);
  11.         OutputStream outputStream = response.getOutputStream();
  12.         byte[] buffer = new byte[4096];
  13.         int bytesRead;
  14.         while ((bytesRead = inputStream.read(buffer)) != -1) {
  15.                 outputStream.write(buffer, 0, bytesRead);
  16.         }
  17.         inputStream.close();
  18.         outputStream.close();
  19. }
复制代码
详细代码可以参考附件工程,大家可以将附件下载到本地,使用ide或者其他代码编辑器打开这个maven工程,并加载相关依赖,然后启动DemoApplication.java这个启动项即可,以下是效果展示:
sjs前后端.gif911447448.png

demo.rar

86.75 KB, 下载次数: 254

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部