.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>

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

被折叠的 条评论
为什么被折叠?



