利用SJS数据流实现前后端的文件传输
本帖最后由 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(, 'test.sjs')
// 也可以封装成blob,spread.open()中直接传递blob即可
// var blob = new Blob(, {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;
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.close();
}详细代码可以参考附件工程,大家可以将附件下载到本地,使用ide或者其他代码编辑器打开这个maven工程,并加载相关依赖,然后启动DemoApplication.java这个启动项即可,以下是效果展示:
页:
[1]