vue+webapi文件上传与下载

vue+webapi文件上传

话不多说直接上本人测试代码

VUE前端

<template>
  <div class="upload-container">
    <el-upload
      drag
      action="/"
      multiple
      ref="upload"
      :limit="10"
      :file-list="fileList"
      :before-upload="beforeUpload"
      :http-request="checkedFile"
      :onRemove="removeFile"
      accept="application/epub+zip"
      class="image-upload"
    >
      <i class="el-icon-upload" />
      <div v-if="fileList.length === 0" class="el-upload__text">
        请将电子书拖入或 <em>点击上传</em>
      </div>
      <div v-else class="el-upload__text">图书已上传</div>
    </el-upload>
  </div>
</template>

<script>
// import SparkMD5 from 'spark-md5'
import store from "../../store";
import { uuid } from "vue-uuid";
import axios from "axios";

export default {
  props: {
    fileList: {
      type: Array,
      default() {
        return [];
      },
    },
    disabled: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      maxSize: 1024 * 1024 * 1024 * 1024, // 上传最大文件限制
      multiUploadSize: 10 * 1024 * 1024, // 大于这个大小的文件使用分块上传(后端可以支持断点续传)
      eachSize: 10 * 1024 * 1024, // 每块文件大小
      requestCancelQueue: {}, // 请求方法队列(调用取消上传
      cancelRequset: "",
    };
  },
  mounted() {},
  methods: {
    beforeUpload(file) {
      const { maxSize, getSize } = this;
      if (file.size > maxSize) {
        this.$message({
          message: `您选择的文件大于${getSize(maxSize)}`,
          type: "error",
        });
        return false;
      }
      return true;
    },
    checkedFile(options) {
      const guid = uuid.v1();
      this.uploadFile(options, guid);
      const prom = new Promise((resolve, reject) => {});
      prom.abort = () => {};
      return prom;
    },
    async uploadFile(options, guid) {
      const startTime = new Date();
      const { multiUploadSize, splitUpload, singleUpload } = this;
      const { file, onProgress, onSuccess, onError } = options;
      const uploadFunc =
        file.size > multiUploadSize ? splitUpload : singleUpload;
      try {
        await uploadFunc(file, guid, onProgress);
        const endTime = new Date();
        let time = this.getDateDiff(startTime, endTime, "second");
        this.$message({
          message: "上传成功 用时:" + time.toString() + "S",
          type: "success",
        });
        onSuccess();
      } catch (e) {
        this.$message({
          message: e.message,
          type: "error",
        });
        onError();
      }
    },
    // 格式化文件大小显示文字
    getSize(size) {
      return size > 1024
        ? size / 1024 > 1024
          ? size / (1024 * 1024) >= 1024
            ? (size / (1024 * 1024 * 1024)).toFixed(2) + "GB"
            : (size / (1024 * 1024)).toFixed(2) + "MB"
          : (size / 1024).toFixed(2) + "KB"
        : size.toFixed(2) + "B";
    },
    // 单文件直接上传
    singleUpload(file, guid, onProgress) {
      return this.postFile(
        { file, guid: guid, fileName: file.fileName, fullSize: file.size },
        onProgress
      ).then((res) => {
        onProgress({ percent: 100 });
        return Promise.resolve(res);
      });
    },
    // 大文件分块上传
    splitUpload(file, guid, onProgress) {
      return new Promise(async (resolve, reject) => {
        try {
          const date = this.getDate();
          const { eachSize } = this;
          const chunks = Math.ceil(file.size / eachSize);
          const fileChunks = await this.splitFile(file, eachSize, chunks);
          let currentChunk = 0;
          for (let i = 0; i < fileChunks.length; i++) {
            // 服务端检测已经上传到第currentChunk块了,那就直接跳到第currentChunk块,实现断点续传
            if (Number(currentChunk) === i) {
              // 每块上传完后则返回需要提交的下一块的index
              currentChunk = await this.postFile(
                {
                  chunked: true,
                  chunk: i,
                  chunks,
                  eachSize,
                  fileName: file.name,
                  fullSize: file.size,
                  guid: guid,
                  date: date,
                  file: fileChunks[i],
                },
                onProgress
              ).then((res) => {
                let percent = 0;
                if (res < fileChunks.length - 1) {
                  percent = Number(
                    (
                      (((currentChunk + 1) * eachSize) / file.size) *
                      100
                    ).toFixed(2)
                  );
                } else {
                  percent = 99;
                }
                onProgress({ percent: percent });
                return Promise.resolve(res);
              });
            }
          }
          const isValidate = await this.validateFile({
            chunks: fileChunks.length,
            fileName: file.name,
            fullSize: file.size,
            guid: guid,
          });
          if (!isValidate) {
            throw new Error("文件校验异常");
          }
          resolve();
        } catch (e) {
          reject(e);
        }
      });
    },
    // 文件分块,利用Array.prototype.slice方法
    splitFile(file, eachSize, chunks) {
      try {
        const fileChunk = [];
        for (let chunk = 0; chunks > 0; chunks--) {
          fileChunk.push(file.slice(chunk, chunk + eachSize));
          chunk += eachSize;
        }
        return fileChunk;
      } catch (e) {
        console.error(e);
      }
    },
    // 删除列表中的文件
    async removeFile(file) {
      this.cancelRequset = file.uid;
      if (
        this.requestCancelQueue[file.uid] !== null &&
        this.requestCancelQueue[file.uid] !== undefined
      ) {
        this.requestCancelQueue[file.uid]();
        delete this.requestCancelQueue[file.uid];
      } else {
        let num = 0;
        this.$refs.upload.uploadFiles.map((item) => {
          console.log(item.uid);
          if (item.uid === file.uid) {
            this.$refs.upload.uploadFiles.splice(num, 1);
          }
          num++;
        });
      }
      return true;
    },
    // 提交文件方法,将参数转换为FormData, 然后通过axios发起请求
    async postFile(param, onProgress) {
      const formData = new FormData();
      for (let p in param) {
        formData.append(p, param[p]);
      }
      let CancelToken = axios.CancelToken;
      let self = this;
      const config = {
        cancelToken: new CancelToken(function executor(cancel) {
          self.requestCancelQueue[param.uid] = cancel;
        }),
        headers: {
          "Content-Type": "multipart/form-data",
        },
        onUploadProgress: (e) => {
          if (param.chunked) {
            e.percent = Number(
              (
                ((param.chunk * (param.eachSize - 1) + e.loaded) /
                  param.fullSize) *
                100
              ).toFixed(2)
            );
          } else {
            e.percent = Number(((e.loaded / e.total) * 100).toFixed(2));
          }
          onProgress(e);
        },
      };
      if (this.cancelRequset === param.uid) {
        self.requestCancelQueue[param.uid]();
        delete this.requestCancelQueue[param.uid];
        this.cancelRequset = "";
        console.log(this.cancelRequset);
        throw new Error("取消上传");
      } else {
        let res = await store.dispatch("upload/fileSave", formData, config);
        return res;
      }
    },
    // 文件校验方法
    async validateFile(file) {
      let res = await store.dispatch("upload/fileMerge", file);
      return res;
    },
    getDateDiff(startTime, endTime, diffType) {
      diffType = diffType.toLowerCase();
      let num = 1;
      if (diffType === "second") {
        num = 1000;
      } else if (diffType === "minute") {
        num = 1000 * 60;
      } else if (diffType === "hour") {
        num = 1000 * 60 * 60;
      } else {
        num = 1000 * 60 * 60 * 24;
      }
      return parseInt(
        (endTime.getTime() - startTime.getTime()) / parseInt(num)
      );
    },
    getDate() {
      let nowDate = new Date();
      let date = {
        year: nowDate.getFullYear(),
        month: nowDate.getMonth() + 1,
        date: nowDate.getDate(),
      };
      let systemDate = date.year + "-" + date.month + "-" + date.date;
      return systemDate;
    },
  },
};
</script>

后端

[HttpPost]
        public ResultModel fileSave()
        {
            var files = HttpContext.Current.Request.Files;
            var form = HttpContext.Current.Request.Form;
            string chunk = form["chunk"];
            string guid = form["guid"];

            //文件保存目录路径 
            string SaveTempPath = "~/FileCollection/";
            string dirTempPath = HttpContext.Current.Server.MapPath(SaveTempPath);

            ResultModel message = new ResultModel();
            var chunked = form["chunked"];
            if (chunked != null && chunked == "true")
            {
                message.data = Convert.ToInt32(chunk) + 1;
                string filePath = Path.Combine(dirTempPath, "TemporaryFiles", guid);
                if (!Directory.Exists(filePath))
                {
                    Directory.CreateDirectory(filePath);
                }

                for (int i = 0; i < files.Count; i++)
                {
                    var file = files[i];
                    //如果有文件
                    if (file.ContentLength > 0)
                    {
                        string dirPath = Path.Combine(filePath, $"{file.FileName}_{chunk}");
                        file.SaveAs(dirPath);
                    }
                }
            }
            else
            {
                string date = DateTime.Now.ToString("yyyy-MM-dd");
                string filePath = Path.Combine(dirTempPath, date, guid);
                if (!Directory.Exists(filePath))
                {
                    Directory.CreateDirectory(filePath);
                }

                for (int i = 0; i < files.Count; i++)
                {
                    var file = files[i];
                    //如果有文件
                    if (file.ContentLength > 0)
                    {
                        string dirPath = Path.Combine(filePath, file.FileName);
                        if (!File.Exists(dirPath))
                        {
                            file.SaveAs(dirPath);
                            string FilePath = $"/FileCollection/{date}/{guid}/{file.FileName}";
                            string SQL = string.Format(@"insert into tab_File (UserName,FileName,FileSize,FilePath) values('{0}','{1}','{2}','{3}')"
                                                    , "小范", file.FileName, Convert.ToInt64(form["fullSize"]), FilePath);
                            int flag = new DBHelper().Execute(SQL);
                        }
                    }
                }
            }
            message.code = 0;
            message.msg = "上传成功";
            return message;
        }

        [HttpPost]
        public async Task<ResultModel> fileMerge([FromBody] FileValidDto valid)
        {
            ResultModel message = new ResultModel { code = 0 };
            string fileName = valid.fileName;
            if (string.IsNullOrEmpty(fileName))
            {
                message.msg = "文件名不能为空";
                message.data = false;
                return message;
            }
            //最终上传完成后,请求合并返回合并消息
            try
            {
                //文件保存目录路径 
                string SaveTempPath = "~/FileCollection/";
                string dirTempPath = HttpContext.Current.Server.MapPath(SaveTempPath);
                string guid = valid.guid;
                int fileCount = valid.chunks;

                string filePath = Path.Combine(dirTempPath, "TemporaryFiles", guid);
                var files = Directory.GetFiles(filePath);
                if (fileCount != files.Count())
                {
                    Directory.Delete(filePath, true);
                    message.msg = "文件上传失败";
                    message.data = false;
                    return message;
                }
                string date = DateTime.Now.ToString("yyyy-MM-dd");
                string fileFinalPath = Path.Combine(dirTempPath, date, guid);
                if (!Directory.Exists(fileFinalPath))
                {
                    Directory.CreateDirectory(fileFinalPath);
                }
                string fileFinalName = Path.Combine(fileFinalPath, fileName);
                FileStream fs = new FileStream(fileFinalName, FileMode.Create);
                foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))
                {
                    var bytes = File.ReadAllBytes(part);
                    await fs.WriteAsync(bytes, 0, bytes.Length);
                    File.Delete(part);//删除分块
                }
                fs.Close();
              
                Directory.Delete(filePath);
               
                string FilePath = $"/FileCollection/{date}/{guid}/{fileName}";
                string SQL = string.Format(@"insert into tab_File (UserName,FileName,FileSize,FilePath) values('{0}','{1}','{2}','{3}')"
                                        , "小范", fileName, valid.fullSize, FilePath);
                int flag = new DBHelper().Execute(SQL);
                message.msg = "上传成功";
                message.data = true;
            }
            catch (Exception ex)
            {
                message.code = 1;
                message.msg = "合并文件失败,请重新上传";
            }
            return message;
        }

        [HttpPost]
        public ResultModel FileDownload()
        {
            var form = HttpContext.Current.Request.Form;
            var fid = form["fid"];
            try
            {
                DataSet ds = new DBHelper().GetDataSet("select * from tab_File where id=" + fid);
                var list = Command.DataSetToList<DataBase.Model.FileModel>(ds).FirstOrDefault();
                //文件保存目录路径 
                string filePath = Path.Combine(HttpContext.Current.Server.MapPath("~/"), list.FilePath);
                return new ResultModel
                {
                    code = 0,
                    msg = "下载",
                    data = filePath
                };
            }
            catch (Exception ex)
            {
                return new ResultModel
                {
                    code = 0,
                    msg = ex.Message
                };
            }
        }

vue+webapi文件下载

VUE前端

事件
 <el-button
              size="mini"
              @click="handleDownLoad(scope.$index, scope.row)"
              >下载</el-button
            >
方法
 handleDownLoad(index, row) {
      var param = new FormData();
      param.append("fid", index);
      param.append("fileName", row.FileName);
      let res = store.dispatch("upload/getFileFrom", row.Id);
      const blob = new Blob([res.data]); //new Blob([res])中不加data就会返回下图中[objece objece]内容(少取一层)
      const fileName = row.FileName; //下载文件名称
      const elink = document.createElement("a");
      elink.download = fileName;
      elink.style.display = "none";
      elink.href = URL.createObjectURL(blob);
      document.body.appendChild(elink);
      elink.click();
      URL.revokeObjectURL(elink.href); // 释放URL 对象
    },
路由
import { getFileFrom } from '@/api/upload'

const actions = {
  // getFileFrom
  getFileFrom({ commit }, fid) {
    return new Promise((resolve, reject) => {
      getFileFrom(fid).then(response => {
        resolve(response)
        //resolve(response.data)
      }).catch(error => {
        reject(error)
      })
    })
  }
}

export default {
  namespaced: true,
  actions
}

export function getFileFrom(fid) {
  return request({
    url: '/book/getFileFrom?fid=' + fid,
    method: 'get',
  })
}

webapi后端

		//响应的MimeType类型
        private const string MimeType = "application/octet-stream";
        /// <summary>
        /// 缓冲区大小
        /// </summary>
        private const int BufferSize = 80 * 1024;
        [HttpGet]
        public ResultModel GetFileFrom(int fid)
        {
            try
            {
                DataSet ds = new DBHelper().GetDataSet("select * from tab_File where id=" + fid);
                var list = Command.DataSetToList<DataBase.Model.FileModel>(ds).FirstOrDefault();
                var FilePath = System.Web.Hosting.HostingEnvironment.MapPath("~"+list.FilePath); //获取文件路径
                var fullFilePath = FilePath;
                if (!File.Exists(fullFilePath))
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }
                FileStream fileStream = File.Open(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                var response = new HttpResponseMessage();
                response.Content = new StreamContent(fileStream, BufferSize);
                response.Content.Headers.ContentDisposition
                    = new ContentDispositionHeaderValue("attachment") { FileName = list.FileName };//list.FileName 文件名称
                response.Content.Headers.ContentType
                    = new MediaTypeHeaderValue(MimeType);
                response.Content.Headers.ContentLength
                    = fileStream.Length;
                //return response;
                return new ResultModel
                {
                    code = 0,
                    msg = "下载",
                    data = response
                };
            }
            catch(Exception ex)
            {
                return new ResultModel
                {
                    code = 0,
                    msg = ex.Message
                };
            }
        }
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值