美文网首页
Vue实现文件上传(单文件、多文件、分片上传)

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

作者: 二营长家的张大炮 | 来源:发表于2019-05-04 11:46 被阅读0次

    前端使用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
    

    处理上传

    @Service(value = "fileSerice")
    public class FileService implements IFileService {
    
        @Autowired
        private FileMapper fileMapper;
    
        //    当前时间戳
        SimpleDateFormat dformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        @Override
        public Map<String,Object> insertfile(MultipartFile file,long uploader) {
    //        文件本地存储位置
            String filepath = "D:\\workspace\\imgs";
    
    //        文件后缀名
            String extension = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf('.') + 1);
    //        文件前缀名
            String suffix = MD5Utils.md5(file.getOriginalFilename());
    //        拼接成新的文件名
            String fileName = suffix + "." + extension;
    
    //         文件存储到数据库的地址
            String url = "http://127.0.0.1:9898/" + fileName;
            File dest = new File(filepath + "/" + fileName);
            try {
                file.transferTo(dest);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String md5 = FileUtils.getFileMD5(dest);
    
            Map<String, Object> filemaps = new HashMap<>();
    
            filemaps.put("filename",file.getOriginalFilename());
            filemaps.put("length",dest.length());
            filemaps.put("md5",md5);
            filemaps.put("url",url);
            filemaps.put("uploader",uploader);
            filemaps.put("uploadDate", dformat.format(new Date()));
    
            Integer num = fileMapper.insertFile(url, md5, file.getOriginalFilename(), dest.length(), uploader,0,uploader, dformat.format(new Date()));
            if (num != 1) {
                throw new OperationFailException();
            }
            return filemaps;
        }
    }
    

    接口部分代码

    /**
     *文件上传
     * zpwan
     * 2019/3/25
     */
    @RestController
    @CrossOrigin
    public class FileController {
        @Autowired
        private FileService fileService;
    
    
        /**
         * 文件上传
         * @param file
         * @return
         */
        @PostMapping(value="/filemodule/file/upload")
        public ResultResponse handleUpload(
                @RequestParam(value = "file", required = true) MultipartFile file,
                HttpServletRequest request
        ) {
            String token = request.getHeader("token");
    
            Long userId = JsonWebTokenUtils.getAppUID(token);
            if (file.isEmpty()) {
                return new ResultResponse(501, "文件为空,请重新上传");
            } else {
                Map<String, Object> fileMaps = fileService.insertfile(file,userId);
                return new ResultResponse(200, "上传成功", fileMaps);
            }
        }
    
    }
    

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

    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);
    }
    

    相关文章

      网友评论

          本文标题:Vue实现文件上传(单文件、多文件、分片上传)

          本文链接:https://www.haomeiwen.com/subject/ybycoqtx.html