news 2026/4/23 14:12:42

教育行业网页应用如何集成文件夹上传组件?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
教育行业网页应用如何集成文件夹上传组件?

开发者日记:2023年X月X日 星期X 长沙 晴

项目背景
今日正式启动客户的大文件传输系统项目,需求明确:支持20G文件/文件夹上传下载、跨平台(Windows/macOS/Linux)、全浏览器兼容(含IE8)、断点续传、保留文件夹层级结构。后端使用**.NET Core**(而非PHP),数据库改为SQL Server,存储仍用阿里云OSS,前端为Vue3 CLI + WebUploader/H5。客户强调高频文件夹上传场景,需极致优化用户体验。免费开源代码和7*24支持的压力依旧,但技术栈调整带来新挑战。


技术选型与调整

  1. 前端框架

    • Vue3 CLI:维持组件化开发,但需适配IE8的Polyfill(如babel-polyfill)。
    • WebUploader:核心上传组件,需深度定制文件夹解析逻辑。
    • H5 File API:现代浏览器备用方案,IE8回退到Flash上传。
  2. 后端架构

    • .NET Core:替代PHP,利用IFormFile处理分片,System.Data.SqlClient操作SQL Server。
    • SQL Server:存储文件元数据(路径、分片状态、用户ID)。
  3. 核心难点升级

    • 高频文件夹上传:需优化递归解析性能,避免前端卡顿。
    • 断点续传稳定性:SQL Server事务保证分片记录一致性。
    • IE8兼容性:Flash上传需处理跨域问题(crossdomain.xml)。

前端代码优化(Vue3 + WebUploader)

1. 强化文件夹上传逻辑
// src/components/FolderUploader.vueimport{ref,onMounted}from'vue';importWebUploaderfrom'webuploader';import'webuploader/dist/webuploader.css';exportdefault{setup(){constuploader=ref(null);constfolderTree=ref([]);// 存储文件夹层级结构onMounted(()=>{// 动态加载Flash(IE8兼容)if(!WebUploader.Uploader.support('HTML5')){WebUploader.Uploader.register({name:'flash',fn:()=>'/assets/Uploader.swf'});}uploader.value=newWebUploader.Uploader({swf:'/assets/Uploader.swf',server:'/api/upload',pick:'#folderPicker',chunked:true,chunkSize:4*1024*1024,// 4MB分片formData:{fileId:'',isDir:false,relativePath:''// 关键:记录文件相对路径}});// 监听文件夹选择(需配合input[directory])document.getElementById('folderInput').addEventListener('change',(e)=>{constitems=e.target.files;if(items){parseFolder(items);// 递归解析文件夹}});});// 递归解析文件夹(兼容现代浏览器)constparseFolder=(items)=>{consttree=[];for(leti=0;i<items.length;i++){constfile=items[i];constpath=file.webkitRelativePath||file.name;// 相对路径constsegments=path.split('/');// 构建树形结构letcurrentLevel=tree;segments.slice(0,-1).forEach(segment=>{letdir=currentLevel.find(item=>item.name===segment);if(!dir){dir={name:segment,type:'directory',children:[]};currentLevel.push(dir);}currentLevel=dir.children;});// 添加文件节点currentLevel.push({name:segments.pop(),type:'file',file:file,relativePath:path});}folderTree.value=tree;uploadFolder(tree);};// 上传文件夹内容constuploadFolder=(tree)=>{tree.forEach(node=>{if(node.type==='directory'){uploadFolder(node.children);// 递归上传子目录}else{constformData=uploader.value.option('formData');formData.relativePath=node.relativePath;uploader.value.addFile(node.file,node.relativePath);}});};return{uploader,folderTree};}};
2. IE8兼容性处理

后端代码实现(.NET Core + SQL Server)

1. 分片上传接口
// Controllers/UploadController.csusingMicrosoft.AspNetCore.Mvc;usingSystem.Data.SqlClient;usingSystem.IO;[ApiController][Route("api/upload")]publicclassUploadController:ControllerBase{privatereadonlyIConfiguration_config;publicUploadController(IConfigurationconfig)=>_config=config;[HttpPost]publicasyncTaskUpload([FromForm]UploadModelmodel){varfileId=model.FileId??Guid.NewGuid().ToString();vartempDir=Path.Combine("/tmp/uploads",fileId);Directory.CreateDirectory(tempDir);// 保存分片varchunkPath=Path.Combine(tempDir,$"chunk_{model.ChunkIndex}");using(varstream=newFileStream(chunkPath,FileMode.Create)){awaitmodel.File.CopyToAsync(stream);}// 记录分片状态到SQL Serverusing(varconn=newSqlConnection(_config.GetConnectionString("Default"))){awaitconn.OpenAsync();varcmd=newSqlCommand(@"MERGE INTO UploadProgress AS target USING (VALUES (@fileId, @chunkIndex, @totalChunks)) AS source (FileId, ChunkIndex, TotalChunks) ON target.FileId = source.FileId AND target.ChunkIndex = source.ChunkIndex WHEN NOT MATCHED THEN INSERT (FileId, ChunkIndex, TotalChunks, UploadedAt) VALUES (source.FileId, source.ChunkIndex, source.TotalChunks, GETDATE());",conn);cmd.Parameters.AddWithValue("@fileId",fileId);cmd.Parameters.AddWithValue("@chunkIndex",model.ChunkIndex);cmd.Parameters.AddWithValue("@totalChunks",model.TotalChunks);awaitcmd.ExecuteNonQueryAsync();}// 如果是最后一块,合并并上传OSSif(model.ChunkIndex==model.TotalChunks-1){varfinalPath=Path.Combine(tempDir,"final_file");using(varoutput=System.IO.File.Create(finalPath)){for(inti=0;i<model.TotalChunks;i++){varchunk=System.IO.File.ReadAllBytes(Path.Combine(tempDir,$"chunk_{i}"));awaitoutput.WriteAsync(chunk,0,chunk.Length);}}// 上传OSS(需引入阿里云OSS SDK)varclient=newOSSClient("endpoint","accessKey","secretKey");awaitclient.PutObjectAsync("bucket-name",$"uploads/{fileId}",finalPath);// 清理临时文件Directory.Delete(tempDir,true);}returnOk(new{success=true,fileId});}}publicclassUploadModel{publicIFormFileFile{get;set;}publicstringFileId{get;set;}publicintChunkIndex{get;set;}publicintTotalChunks{get;set;}publicstringRelativePath{get;set;}// 文件夹层级路径}
2. SQL Server表结构
CREATETABLEUploadProgress(IdINTIDENTITY(1,1)PRIMARYKEY,FileId NVARCHAR(64)NOTNULL,ChunkIndexINTNOTNULL,TotalChunksINTNOTNULL,UploadedAt DATETIME2DEFAULTGETDATE(),UNIQUE(FileId,ChunkIndex));

断点续传实现

1. 前端恢复逻辑
// 检查未完成上传constcheckResume=async(fileId)=>{constres=awaitfetch(`/api/upload/progress?fileId=${fileId}`);constdata=awaitres.json();if(data.completedChunks<data.totalChunks){uploader.value.option('formData',{fileId,chunk:data.completedChunks});uploader.value.upload();}};// 本地存储fileId(即使浏览器关闭)window.addEventListener('beforeunload',()=>{if(uploader.value.getFiles().length>0){localStorage.setItem('lastUploadId',uploader.value.option('formData').fileId);}});
2. 后端进度查询
[HttpGet("progress")]publicasyncTaskGetProgress(stringfileId){using(varconn=newSqlConnection(_config.GetConnectionString("Default"))){awaitconn.OpenAsync();varcmd=newSqlCommand("SELECT COUNT(*) AS Completed FROM UploadProgress WHERE FileId = @fileId",conn);cmd.Parameters.AddWithValue("@fileId",fileId);varcount=(int)awaitcmd.ExecuteScalarAsync();returnOk(new{completedChunks=count});}}

今日总结

  • 进展:完成文件夹层级解析和.NET Core分片上传逻辑,IE8兼容性方案验证通过。
  • 问题
    1. WebUploader在IE8下对大文件夹性能较差,需优化DOM操作。
    2. SQL Server事务需加强,避免分片记录残留。
  • 明日计划
    1. 实现OSS分片上传(避免本地合并临时文件)。
    2. 编写完整的错误处理和日志系统。

求助:若有熟悉.NET Core文件处理或SQL Server优化的高手,欢迎加入QQ群374992201指导!代码将完全开源回馈社区。


(注:实际项目需补充安全校验、OSS直传和性能监控代码。)

设置框架

安装.NET Framework 4.7.2
https://dotnet.microsoft.com/en-us/download/dotnet-framework/net472
框架选择4.7.2

添加3rd引用

编译项目

NOSQL

NOSQL无需任何配置可直接访问页面进行测试

SQL

使用IIS
大文件上传测试推荐使用IIS以获取更高性能。

使用IIS Express

小文件上传测试可以使用IIS Express

创建数据库

配置数据库连接信息

检查数据库配置

访问页面进行测试


相关参考:
文件保存位置,

效果预览

文件上传

文件刷新续传

支持离线保存文件进度,在关闭浏览器,刷新浏览器后进行不丢失,仍然能够继续上传

文件夹上传

支持上传文件夹并保留层级结构,同样支持进度信息离线保存,刷新页面,关闭页面,重启系统不丢失上传进度。

批量下载

支持文件批量下载

下载续传

文件下载支持离线保存进度信息,刷新页面,关闭页面,重启系统均不会丢失进度信息。

文件夹下载

支持下载文件夹,并保留层级结构,不打包,不占用服务器资源。

下载完整示例

下载完整示例

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/22 17:26:04

‌AI自动生成“测试数据血缘图”:重构软件测试中的Bug源头追踪范式

一、AI驱动的测试数据血缘图&#xff0c;正在将Bug定位时间从“天级”压缩至“分钟级”‌传统测试中&#xff0c;定位一个线上缺陷常需人工翻查日志、比对代码、追溯数据库变更&#xff0c;耗时数小时甚至数日。而基于AI的‌自动化测试数据血缘图‌&#xff0c;通过动态构建“数…

作者头像 李华
网站建设 2026/4/18 18:22:24

‌AI驱动的测试用例版本对比:新旧版本差异自动标注实战指南

AI已实现测试用例版本差异的语义级自动标注&#xff0c;可节省50%以上维护时间&#xff0c;误漏测率下降30%&#xff0c;并深度集成于CI/CD流水线‌传统测试用例版本对比依赖人工比对、文本差异工具&#xff08;如Git diff&#xff09;或简单字段匹配&#xff0c;无法识别语义变…

作者头像 李华
网站建设 2026/4/23 10:48:26

脑机接口黑客劫持事故:软件测试视角下的安全漏洞与防御策略

事故概述与测试的重要性 2026年1月&#xff0c;全球科技界发生了一起震惊事件&#xff1a;3000名植入NeuraLink脑机接口芯片的用户在睡眠中被黑客集体劫持。攻击者通过远程漏洞&#xff0c;篡改了芯片的神经信号传输模块&#xff0c;导致用户出现短期记忆混乱和肢体失控症状。…

作者头像 李华
网站建设 2026/4/17 9:11:46

《战略方法论》:如何洞察商机进行创新实践(附相关材料下载)

在不确定的市场环境中&#xff0c;企业的核心竞争力往往取决于能否精准捕捉隐藏的商机&#xff0c;并通过高效的创新实践将其转化为可持续的增长动力。而战略方法论&#xff0c;正是串联“商机洞察”与“创新实践”的核心纽带——它为商机挖掘提供系统框架&#xff0c;为创新落…

作者头像 李华
网站建设 2026/4/22 12:42:42

比特币超级周期将至的原因

作者&#xff1a;Arthur Hayes编者注&#xff1a;本文略有删减此处表达的所有观点均为作者个人观点&#xff0c;不应作为投资决策的依据&#xff0c;也不应被视为参与投资交易的推荐或建议。我的神灵们是以可爱毛绒玩具的形象具象化的。在1月和2月北海道滑雪最旺盛的季节&#…

作者头像 李华