Vue实现文件上传(单文件、多文件、分片上传)

发布时间 2023-10-16 10:02:05作者: Xproer-松鼠

前端使用UI封装好的upload组件

1.单文件上传

  <a-upload
            :disabled="!editpersonflag"
            name="avatar"
            listType="picture-card"
            class="avatar-uploader"
            :showUploadList="false"
            :beforeUpload="beforeUpload"
            @change="handleAvatar"
          >
            <img v-if="imageUrl" :src="imageUrl" alt="avatar" style="width:204px;height:164px">
          </a-upload>

 // 处理文件上传
    handleUpload(file) {
      axios({
        url: "http://127.0.0.1:9898/filemodule/file/upload",
        method: "post",
        headers: {
          "Content-Type": "multipart/form-data",
          token:
            localStorage.getItem("token") === null
              ? ""
              : localStorage.getItem("token")
        },
        data: {
          file: file
        },
        transformRequest: [
          function(oldData) {
            var form = new FormData();
            for (let item in oldData) {
              form.append(item, oldData[item]);
            }
            return form;
          }
        ]
      }).then(response => {
        if (response.data.code === 200) {
          this.$message.success("上传成功");
              this.imageUrl = response.data.data.url;
        } else {
          this.$message.error("上传失败");
        }
      });
    },
    beforeUpload() {
      return false;
    },

2.多文件上传

    <!-- 预览图 -->
    <b-row class="evaluate-row">
      <span class="evaluate-span">预览图</span>
      <a-upload multiple :fileList="fileList" :remove="handleRemove" :beforeUpload="beforeUpload">
        <a-button>
          <a-icon type="upload"/>选择文件
        </a-button>
      </a-upload>
      <a-button
        type="primary"
        @click="handlePreviewAvatar"
        :disabled="fileList.length === 0"
        :loading="uploading"
        style="margin-left: 16px"
      >{{uploading ? '上传中' : '开始上传' }}</a-button>
    </b-row>

  handleRemove(file) {
      const index = this.fileList.indexOf(file);
      const newFileList = this.fileList.slice();
      newFileList.splice(index, 1);
      this.fileList = newFileList;
    },
    beforeUpload1(file) {
      this.fileList = [...this.fileList, file];
      return false;
    },
    // 预览图
    handlePreviewAvatar() {
      const previewurls = [];
      for (var i = 0; i < this.fileList.length; i++) {
        axios({
          url: "http://127.0.0.1:9898/filemodule/file/upload",
          method: "post",
          headers: {
            "Content-Type": "multipart/form-data",
            token:
              localStorage.getItem("token") === null
                ? ""
                : localStorage.getItem("token")
          },
          data: {
            file: this.fileList[i]
          },
          transformRequest: [
            function(oldData) {
              var form = new FormData();
              for (let item in oldData) {
                form.append(item, oldData[item]);
              }
              return form;
            }
          ]
        }).then(response => {
          if (response.data.code === 200) {
            this.$message.success("上传成功");
            previewurls.push(response.data.data.url);
            this.previewurls = previewurls;
            console.log(previewurls);
          } else {
            this.$message.error("上传失败");
          }
        });
      }
    },

3.分片上传(使用blob切片对文件进行切割)

 //文件预上传
    handlePrepareUpload() {
      this.uploading = "上传中";
      var file = this.fileList[0];
      const fileSize = file.size; // 文件大小
      this.filesize = fileSize;
      const chunkSize = 1024 * 1024 * 10; // 切片的大小
      const chunks = Math.ceil(fileSize / chunkSize); // 获取切片个数
      const fileReader = new FileReader();
      const spark = new SparkMD5.ArrayBuffer();
      const bolbSlice =
        File.prototype.slice ||
        File.prototype.mozSlice ||
        File.prototype.webkitSlice;
      let currentChunk = 0;

      fileReader.onload = e => {
        const res = e.target.result;
        spark.append(res);
        currentChunk++;
        if (currentChunk < chunks) {
          loadNext();
        } else {
          const md5 = spark.end();
          this.getMd5Checked(md5);
        }
      };

      const loadNext = () => {
        const start = currentChunk * chunkSize;
        const end =
          start + chunkSize > file.size ? file.size : start + chunkSize;
        fileReader.readAsArrayBuffer(bolbSlice.call(file, start, end));
      };
      loadNext();
    },
    getMd5Checked(value) {
      this.fileMD5 = value;
      HttpService.getFileCheckByMd5({ md5: value }).then(response => {
        if (response.data.data.md5 !== value) {
          const { fileList } = this;
          HttpService.getFilePrepare({
            extension: fileList[0].name.slice(
              fileList[0].name.lastIndexOf(".") + 1
            ),
            chunks: Math.ceil(this.fileList[0].size / 1024 / 1024 / 10)
          })
            .then(response => {
              const downloadaddress = response.data.data.url;
              this.downloadaddress = downloadaddress;
              const contextId = response.data.data.contextId;
              this.filecontextId = contextId;
              this.handleUpload(response);
            })
            .catch(error => {
          
            });
        } else {
          // 如果文件之前上传过 则返回数据
          this.uploading = "上传完成";
          this.fileMD5 = response.data.data.md5;
          this.filecontextId = response.data.data.contextId;
          this.downloadaddress = response.data.data.url;
          this.filesize = response.data.data.length;
        }
      });
    },
    // 文件上传
    handleUpload(res) {
      var type = this.fileList[0].type; // 文件类型
      var chunk = 1024 * 1024 * 10; // 每个文件切片大小定为10MB .
      var blobs = [];
      var start = 0;
      //文件切割
      for (var i = 0; i < Math.ceil(this.fileList[0].size / chunk); i++) {
        var end = start + chunk;
        blobs[i] = this.fileList[0].slice(start, end, type);
        start = end;
      }
      var uploads = res.data.data.uploads;
      var count = 0;
      for (var i = 0; i < uploads.length; i++) {
        var params = uploads[i].params;
        var url = uploads[i].host;
        axios({
          url: url,
          method: "post",
          headers: {
            "Content-Type": "multipart/form-data"
          },
          data: {
            appKey: params.appKey,
            contextId: params.contextId,
            expires: params.expires,
            token: params.token,
            file: blobs[i]
          },
          transformRequest: [
            function(oldData) {
              var form = new FormData();
              for (let item in oldData) {
                form.append(item, oldData[item]);
              }
              return form;
            }
          ]
        })
          .then(response => {
            count++;
            if (count === i) {
              HttpService.getFileComplete({
                contextId: this.filecontextId,
                md5: this.fileMD5
              }).then(response => {
                this.uploading = "上传完成";
              });
            }
          })
          .catch(error => {
   
          });
      }
    },

服务端代码
web端上传文件后,后端读取文件并存储到静态资源存储位置,并将地址存进数据库,这样通过地址就能访问到资源了,在这之前我们需要配置服务端存储文件的本地文件夹。

#    配置静态文件夹,这是我的图片服务器(可以直接端口地址加文件夹内的名称可以直接访问该文件)
  resources:
        static-locations: classpath:/META-INF/resources/,classpath:/resources/,\
                            classpath:/static/,classpath:/public/,file:D:\workspace\imgs

处理上传

接口部分代码

/**
 *文件上传
 * zpwan
 * 2019/3/25
 */

最近又对之前代码进行了封装,封装成一个函数,实现复用性:

import axios from 'axios'
import { AxiosResponse } from 'axios'
export const handleFileUpload = async (file: File, callback: Function) => {

    const res: AxiosResponse<ApiResponse<FileInfo>> = await axios({
        url: "http://127.0.0.1:9898/blogManage/filemodule/upload",
        method: "post",
        headers: {
            "Content-Type": "multipart/form-data",
            'token': localStorage.getItem('token') === null ? '' : localStorage.getItem('token')
        },
        data: {
            file: file
        },
        transformRequest: [
            function (oldData) {
                var form = new FormData();
                for (let item in oldData) {
                    form.append(item, oldData[item]);
                }
                return form;
            }
        ]
    })
    callback(res.data);
}