本帖最后由 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文件进行加载和保存,如果我们在文件落盘时拿到数据流,直接传输给后端,便不需要在前端进行落盘处理了,拿到数据流后直接传输给后端即可 - spread.save(
- function (blob) {
- var xhr = new XMLHttpRequest();
- xhr.open("POST", "/sjs/add", true);
- var formData = new FormData();
- formData.append('sjs', blob);
- formData.append('fileName', inputValue);
- xhr.onreadystatechange = function () {
- if (xhr.readyState === XMLHttpRequest.DONE) {
- if (xhr.status === 200) {
- console.log(xhr.responseText);
- var result = JSON.parse(xhr.responseText);
- var code = result.code;
- if (code === 200) {
- console.log("保存成功")
- }
- } else {
- console.log(xhr.status);
- console.log(xhr.responseText);
- }
- }
- };
- xhr.send(formData);
- },
- function (e) {
- console.log(e);
- }
- );
复制代码- var spread = GC.Spread.Sheets.findControl(document.getElementById("ss"));
- xhr.open("get", "/sjs/get?fileName=" + inputValue)
- xhr.responseType = "blob"
- xhr.addEventListener("loadend", function () {
- if (this.readyState == 4 && this.status == 200) {
- let file = new File([this.response], 'test.sjs')
- // 也可以封装成blob,spread.open()中直接传递blob即可
- // var blob = new Blob([this.response], {type:'application/zip'});
- spread.open(file)
- }
- })
- xhr.send()
复制代码
后端可以使用我们的GCExcel对数据进行落盘,具体是用时可以将落盘的路径保存在关系型数据库中,例如mysql中,路径保存我们不做介绍,我们将核心的落盘的controller层方法进行实践: 1. 接收数据流并落盘 - @PostMapping("/add")
- public R addSJS(@RequestParam("sjs") MultipartFile sjsFile, @RequestParam("fileName") String fileName) throws IOException {
- int userId = 4;
- // 获取数据
- String filePath = "data/" + userId + "/";
- File directory = new File(filePath);
- if (!directory.exists()) {
- boolean success = directory.mkdirs();
- if (success) {
- System.out.println("文件夹创建成功!");
- } else {
- System.out.println("文件夹创建失败!");
- }
- } else {
- System.out.println("文件夹已存在!");
- }
- // 创建一个新的文件流来保存文件。
- InputStream out = null;
- try {
- out = sjsFile.getInputStream();
- } catch (FileNotFoundException e) {
- // 处理文件未找到异常。
- e.printStackTrace();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- // 保存流文件
- Workbook workbook = new Workbook();
- // 将Workbook对象保存为.sjs文件。
- workbook.open(out, OpenFileFormat.Sjs);
- workbook.save(filePath + fileName, SaveFileFormat.Sjs);
- // 一切正常
- return R.success(CodeEnum.SUCCESS,Constants.OK);
- }
复制代码2. 获取文件,并加载为数据流进行传输 - @RequestMapping(value = "/get", method = RequestMethod.GET)
- public void downloadFile(@RequestParam("fileName") String fileName, HttpServletResponse response) throws IOException {
- String ssjsonPath = "data/4/" + fileName;
- File file = new File(ssjsonPath);
- // 设置响应内容类型为二进制流
- response.setContentType("application/octet-stream");
- response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
- response.setHeader("Content-Length", String.valueOf(file.length()));
- // 读取文件并写入响应的输出流
- InputStream inputStream = new FileInputStream(file);
- OutputStream outputStream = response.getOutputStream();
- byte[] buffer = new byte[4096];
- int bytesRead;
- while ((bytesRead = inputStream.read(buffer)) != -1) {
- outputStream.write(buffer, 0, bytesRead);
- }
- inputStream.close();
- outputStream.close();
- }
复制代码详细代码可以参考附件工程,大家可以将附件下载到本地,使用ide或者其他代码编辑器打开这个maven工程,并加载相关依赖,然后启动DemoApplication.java这个启动项即可,以下是效果展示:
|