前后端文件流同步实践
本帖最后由 ann 于 2022-8-25 12:04 编辑日常向开发中,如果是前后端分离的项目,同时涉及到文件的操作,难免存在文件传输的需求,本质上是对文件流的传输和解析,下面我们通过代码实战来直观感受下。
一、前端同步文件到后端SpreadJs在保存文件时,借助GC.Spread.Excel.IO组件的save方法,可以获取到文件的blob对象。因此在前端项目中可通过调用save方法,获取到blob对象,然后重写自己的文件传输逻辑。
SpreadJs导入导出Excel官网实例:https://demo.grapecity.com.cn/sp ... mport-export/purejs
Blob对象简介:BLOB 简介
https://xkhimi6hls.feishu.cn/space/api/box/stream/download/asynccode/?code=ZGVlMWRmY2VkYWRlZDI3ZTM1MjcyNDUzZjRlYmY3MGFfWjlacG1HTmQwakZvSWdIcW1ZRTk3R2MxYTBwRThxNW9fVG9rZW46Ym94Y25LRFdDb1dIUHNPaFhvcmp1bkNBTG1mXzE2NjEzOTk3NTc6MTY2MTQwMzM1N19WNA
1.1 前端实现-React前端借助SpreadJs的在线表格编辑器,导入本地Excel文件,借助excelIo.save方法获取到文件的Blob对象,然后以表单的方式提交请求到后端。
前端代码
import React from 'react'
import {Button, Col, message, Space, Switch} from "antd";
import '@grapecity/spread-sheets-resources-zh';
import '@grapecity/spread-sheets-designer-resources-cn';
import {Designer} from '@grapecity/spread-sheets-designer-react';
import GC from "@grapecity/spread-sheets";
import * as ExcelIo from "@grapecity/spread-excelio"
GC.Spread.Common.CultureManager.culture("zh-cn");
const config = GC.Spread.Sheets.Designer.DefaultConfig
export default class SpreadJs extends React.Component {
constructor(props) {
super(props);
this.designer = null
this.state = {
spread: null,
}
}
componentDidMount() {
}
onClick = () => {
let spread = this.state.spread;
let json = spread.toJSON();
this.excelIo = new ExcelIo.IO();
this.excelIo.save(json, function (blob) {
let formData = new FormData();
formData.append("content", blob,"111.xlsx");
let request = new XMLHttpRequest();
request.open("POST", "http://localhost:8080/send/file/blob",)
request.send(formData)
}, function (e) {
console.log(e);
});
//也可直接将string对象转换为Blob然后传输到后端
//let blob=new Blob(,{type:"application/json"})
}
/**
* 初始化spread
* @param designer
*/
designerInitialized = (designer) => {
this.designer = designer;
let spread = this.designer.getWorkbook()
this.setState({spread})
}
render() {
return (
<div>
<Col>
<Button type='primary' onClick={this.onClick}
style={{backgroundColor: '#22e7ff', marginLeft: 20, marginTop: 5}}>向后端传输文件</Button>
</Col>
<Designer
spreadOptions={{sheetCount: 1}}
styleInfo={{width: "100%", height: '80vh'}}
config={config}
designerInitialized={this.designerInitialized}
></Designer>
</div>
)
}
}1.2 后端实现-JAVA@RequestMapping(value = "/send/file/blob", produces = {"application/json;charset=utf-8"})
public void sendFileBlob(HttpServletResponse response, HttpServletRequest request) {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
Iterator<String> iter = multiRequest.getFileNames();
while (iter.hasNext()) {
MultipartFile multipartFile = multiRequest.getFile(iter.next());
if (null != multipartFile) {
String fileName = multipartFile.getOriginalFilename();
if (fileName == null || fileName.trim().equals("")) {
continue;
}
//todo 具体的业务逻辑
}
}
}1.3 效果演示
借助SpreadJs的在线表格编辑器,导入本地文档111.xlsx。
https://xkhimi6hls.feishu.cn/space/api/box/stream/download/asynccode/?code=MmNkNWM4ZjM3ZTA3ZDVjNDMzYjYwYmJiYzI1YmU5MTJfVEpRQWJoQTI4UkwyV3NYMlBPTVhqWlRsZDZiVmtGZGpfVG9rZW46Ym94Y25pTldlcVNxOGluZlp2UXp0dkNJckhnXzE2NjEzOTk4NDQ6MTY2MTQwMzQ0NF9WNA
点击“向后端传输文件”按钮,触发文件传输,后端可获取到对应的文件信息。可做具体的业务逻辑。
https://xkhimi6hls.feishu.cn/space/api/box/stream/download/asynccode/?code=MGJiNzk2MzRlNmJiZWVhYjU1NzMxMWFjZDIyZGM1OGNfajVEZ3JrVk5YdjVFbEJlYUlCUGlCNXhyelhDMkRsT2VfVG9rZW46Ym94Y25CQzVrNFRjTzhuTG1Cb0h5NUtaZVdoXzE2NjEzOTk4NDQ6MTY2MTQwMzQ0NF9WNA
二、后端同步文件到前端
从后端后获取文件流同步到前端,然后直接在浏览器中下载
2.1 前端实现-React//加载指定的文件流到前端浏览器下载
loadFile = () => {
let filePath = "/Users/yak/myProject/exceldemo/tttt3.xlsx";
return new Promise((resolve, reject) => {
axios({
method: 'get',
url: "http://localhost:8080/upload/file?filePath=" + filePath,
responseType: 'blob'
}).then(data => {
let blob = data.data;
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "text.xlsx";
link.click();
link.remove();
URL.revokeObjectURL(link.href);}).catch(error => {
reject(error.toString())
})
})
}2.2 后端实现-JAVA
读取本地文件,将其转换为二进制字节流,提供接口给第三方访问。
@GetMapping(value = "/upload/file")
public void download(String filePath, HttpServletResponse response) throws Exception {
ServletOutputStream out = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
FileInputStream inputStream = new FileInputStream(filePath);
String[] filePaths = StringUtil.split(filePath,"/");
byte[] buffer = new byte;
int len;
byteArrayOutputStream = new ByteArrayOutputStream();
while ((len = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
response.addHeader("Content-Disposition", "attachment;filename=" + filePaths);
response.addHeader("Content-Length", "" + byteArrayOutputStream.size());
response.setHeader("filename", filePaths);
response.setContentType("application/octet-stream");
out = response.getOutputStream();
out.write(byteArrayOutputStream.toByteArray());
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
} finally {
// 关闭文件流
if (null != byteArrayOutputStream) {
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
}
if (null != out) {
out.flush();
out.close();
}
}
}2.3 效果演示
前端获取到后端同步的文件流对象
https://xkhimi6hls.feishu.cn/space/api/box/stream/download/asynccode/?code=NjhhYmYyMjRhZTY1M2RiYzM1ODRkMTg5ZmU2ZjFhNjRfQUIwa2hNVzRhQTVFUENDWjRFd3p3Y1ViUWZMeDFTWXZfVG9rZW46Ym94Y25LVjY1dlVvcnFCaGk0WnViU1NKazdnXzE2NjEzOTk5MDg6MTY2MTQwMzUwOF9WNA
浏览器侧的下载实现
https://xkhimi6hls.feishu.cn/space/api/box/stream/download/asynccode/?code=ZWNjMDg2YmU5Y2Y1OTQ1ZDkxNjNlZjg5ZDI3NGM5ODZfS3lvb1czN0IxRFFqVXhVMmZ3bE9lWEFrM3BiekNnbE1fVG9rZW46Ym94Y25wUHl2MGVHa0x6S3V2a211d0hsMjhjXzE2NjEzOTk5MDg6MTY2MTQwMzUwOF9WNA
求完整demo:hjyzw:
页:
[1]