ann 发表于 2022-8-25 11:58:57

前后端文件流同步实践

本帖最后由 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














Derrick.Jiao 发表于 2022-8-25 13:39:03

求完整demo:hjyzw:
页: [1]
查看完整版本: 前后端文件流同步实践