.Net 6 + Vue Element-UI分包上传文件

这篇博客详细介绍了如何在.Net6后端和VueElement-UI前端环境中实现分片上传图片文件。后端通过检查文件类型、大小并合并分片来确保上传的安全性和效率,前端则利用Vue的axios库进行分包上传操作。整个流程涵盖了文件验证、分片上传和文件合并等关键步骤。
.Net 6 + Vue Element-UI分包上传文件

本靓仔纯手写,略略略;
啥都不说直接上代码

接口代码:

/// <summary>
        /// 临时文件夹
        /// </summary>
        private readonly string tempDirectoryName = "TempDirectory";

        /// <summary>
        /// 允许上传的文件类型
        /// </summary>
        private readonly List<string> allowFileExtNames = new List<string>() { ".png", ".jpg", ".icon" };

        /// <summary>
        /// 允许上传文件流头部
        /// png:13780
        /// jpg:255216
        /// </summary>
        private readonly List<string> allowFileStreamHearders = new List<string>() { "255216", "13780" };

       /// <summary>
       /// 上传图片文件
       /// 只允许上传图片
       /// </summary>
       /// <returns></returns>
        [HttpPost]
        public ReturnData<UploadImageModel> UploadImageFile()
        {
            UploadImageModel result = new UploadImageModel();
            try
            {
                var from = Request.Form;
                var requestId = Request.Form["requestId"].ToString();

                var file = Request.Form.Files.FirstOrDefault();
                int total = Convert.ToInt32(Request.Form["total"]);
                int index = Convert.ToInt32(Request.Form["index"]);
                string fileName = Request.Form["fileName"].ToString();

                //文件类型(根据后台枚举而定)
                int fileType = Convert.ToInt32(Request.Form["fileType"]);
                if (fileType != (int)ImageTypeEnum.SoftwareImage)
                {
                    return ReturnDataHelper<UploadImageModel>.Fail("不支持的文件类型", null);
                }

                string extName = Path.GetExtension(fileName);

                #region 上传文件验证
                if (!allowFileExtNames.Contains(extName.ToLower()))
                {
                    return ReturnDataHelper<UploadImageModel>.Fail("不支持的文件类型", null);
                }
                if (file == null)
                {
                    return ReturnDataHelper<UploadImageModel>.Fail("请求中不包含文件", null);
                }
                if (file.Length <= 0)
                {
                    return ReturnDataHelper<UploadImageModel>.Fail("请选择上传文件", null);
                }
                if (file.Length > 1024 * 1024 * 5)
                {
                    return ReturnDataHelper<UploadImageModel>.Fail("文件单片上传不能大于5MB", null);
                }
                #endregion

                #region 设置文件保存路径
                //文件上传基础文件夹
                string saveFileBasePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "Upload", "Images");
                //最终保存文件夹路径
                string finalFilePath = Path.Combine(saveFileBasePath, ((ImageTypeEnum)fileType).ToString());
                //临时文件夹路径
                string tempFilePath = string.Empty;

                //上传第一包文件时
                if (index == 0)
                {
                    requestId = GetTempDirectoryName();
                    tempFilePath = Path.Combine(saveFileBasePath, tempDirectoryName, requestId);

                    //如果临时文件夹已存在,则删除临时文件夹
                    if (Directory.Exists(tempFilePath))
                    {
                        Directory.Delete(tempFilePath, true);
                    }
                }
                else
                {
                    tempFilePath = Path.Combine(saveFileBasePath, tempDirectoryName, requestId);
                }

                //创建文件路径
                if (!Directory.Exists(saveFileBasePath))
                {
                    Directory.CreateDirectory(saveFileBasePath);
                }
                if (!Directory.Exists(tempFilePath))
                {
                    Directory.CreateDirectory(tempFilePath);
                }
                if (!Directory.Exists(finalFilePath))
                {
                    Directory.CreateDirectory(finalFilePath);
                }
                #endregion

                //临时文件保存路径
                string tempFileSavePath = Path.Combine(tempFilePath, index.ToString());
                using (var stream = new FileStream(tempFileSavePath, FileMode.Create))
                {
                    file.CopyTo(stream);
                    stream.Flush();
                }

                if (total == index + 1)
                {
                    //上传完最后一个文件分片后,合并所有文件分片
                    string imageName = FileMerge(finalFilePath, tempFilePath, extName);
                    result.Url = $"{_configuration["application:UploadServerUrl"].TrimEnd('/')}/Upload/Images/{((ImageTypeEnum)fileType)}/{imageName}";
                }
                result.RequestId = requestId;

                return ReturnDataHelper<UploadImageModel>.Success("", result);
            }
            catch (Exception ex)
            {
                Log4NetHelper.WriteExceptionLog("上传文件,UploadFile", ex);
                return ReturnDataHelper<UploadImageModel>.Exception("系统异常", null);
            }
        }

        /// <summary>
        /// 合并文件
        /// </summary>
        /// <param name="saveFilePath">文件类型</param>
        /// <param name="tempFilePath">临时文件夹</param>
        /// <param name="extName">上传文件的扩展名</param>
        /// <returns></returns>
        private string FileMerge(string saveFilePath, string tempFilePath, string extName)
        {
            string fileName = StrCore.GetGuid() + extName;
            try
            {
                //获取临时文件夹下的全部分片
                var files = Directory.GetFiles(tempFilePath);

                if (!Directory.Exists(saveFilePath))
                {
                    Directory.CreateDirectory(saveFilePath);
                }

                //最终的文件保存到的路径
                var finalPath = Path.Combine(saveFilePath, fileName);
                var fs = new FileStream(finalPath, FileMode.Create);
                foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))
                {
                    byte[] bytes = System.IO.File.ReadAllBytes(part);
                    fs.Write(bytes, 0, bytes.Length);
                    //删除分块
                    System.IO.File.Delete(part);
                }
                fs.Close();

                //删除临时文件夹
                Directory.Delete(tempFilePath, true);

                return fileName;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 获取临时文件夹名称
        /// </summary>
        /// <returns></returns>
        private string GetTempDirectoryName()
        {
            RedisHelper redisHelper = new RedisHelper();
            long index = redisHelper.Increment(tempDirectoryName);
            index = index % 100;
            return tempDirectoryName + index;
        }
    }

    /// <summary>
    /// 文件类型枚举
    /// </summary>
    public enum ImageTypeEnum
    {
        /// <summary>
        /// 软件图片
        /// </summary>
        SoftwareImage = 1
    }

    /// <summary>
    /// 上传图片返回参数
    /// </summary>
    public class UploadImageModel
    {
        /// <summary>
        /// 文件访问路径
        /// </summary>
        public string Url { get; set; }

        /// <summary>
        /// 请求id
        /// </summary>
        public string RequestId { get; set; }
    }

前端代码(Vue)

<template>
  <div>
    <el-upload
      action="qqq"
      :auto-upload="true"
      :before-upload="handleInitRequestParam"
      :data="uploadData"
      :http-request="upload"
      list-type="picture-card"
      :multiple="false"
      :on-preview="handlePictureCardPreview"
      :on-remove="handleRemove"
    >
      <i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
      <img alt="" :src="dialogImageUrl" width="100%" />
    </el-dialog>
  </div>
</template>

<script>
  import axios from 'axios' // 引入
  export default {
    data() {
      return {
        dialogImageUrl: '',
        dialogVisible: false,
        uploadData: {
          requestId: '',
          total: 1,
          index: 0,
          fileName: '',
          fileType: 1,
        },
        imageFile: null,
      }
    },
    methods: {
      handleRemove(file, fileList) {
        console.log(file, fileList)
      },
      handlePictureCardPreview(file) {
        this.dialogImageUrl = file.url
        this.dialogVisible = true
      },
      handleInitRequestParam(file) {
        this.imageFile = file
        this.uploadData.fileName = file.name
      },
      async upload() {
        //上传文件单片2MB
        var chunkSize = 1024 * 1024 * 2
        // 总分片数量
        var chunks = Math.ceil(this.imageFile.size / chunkSize)
        this.uploadData.total = chunks

        // 分包上传文件
        for (let index = 0; index < chunks; index++) {
          this.uploadData.index = index
          var tempFile = null
          if (index === chunks - 1) {
            tempFile = this.imageFile.slice(index * chunkSize)
          } else {
            tempFile = this.imageFile.slice(
              index * chunkSize,
              (index + 1) * chunkSize
            )
          }

          // 封装请求参数
          var data = new FormData()
          data.append('file', tempFile)
          data.append('requestId', this.uploadData.requestId)
          data.append('total', this.uploadData.total)
          data.append('index', this.uploadData.index)
          data.append('fileName', this.uploadData.fileName)
          data.append('fileType', this.uploadData.fileType)

          var res = await axios.post(
            'http://127.0.0.1:7001/api/Upload/UploadImageFile',
            data
          )
          if (res.data.code === 200) {
            if (index === chunks - 1) {
              // 最后一包上传成功获取图片地址
              console.log(res.data.data.url)
            }
            // 获取请求id
            this.uploadData.requestId = res.data.data.requestId
          }
        }
      },
    },
  }
</script>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫杨NET

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值