农业营销型网站源码大丰做网站哪家好

张小明 2025/12/19 16:43:09
农业营销型网站源码,大丰做网站哪家好,WordPress添加网页背景图片,wordpress调用分类标签咱是一名福建的“老码农”#xff0c;最近接了个外包项目#xff0c;客户要做大文件上传功能#xff0c;要求还挺细——原生JS实现、20G文件传输、文件夹保留层级、加密传输存储、断点续传兼容IE9… 预算还卡在100块以内#xff08;老板说“小项目不搞虚的”#xff09;。…咱是一名福建的“老码农”最近接了个外包项目客户要做大文件上传功能要求还挺细——原生JS实现、20G文件传输、文件夹保留层级、加密传输存储、断点续传兼容IE9… 预算还卡在100块以内老板说“小项目不搞虚的”。咱一边啃着泡面一边想“这活得整明白不然别说接单了客户都得跑”先唠唠客户的“离谱”需求但必须满足大文件文件夹20G文件1000子文件的文件夹每天批量上传得稳得住。断点续传用户关浏览器、重启电脑都不丢进度咱就想这用户怕不是经常断电。加密传输用SM4/AES存储也加密客户说“数据安全比命重要”。兼容IE9部分用户还在Win7IE9咱叹气“这浏览器比我还老…”。非打包下载几万文件打包服务器直接崩客户“之前打包方案被骂惨了”。咱的“土味”解决方案能跑就行没找开源组件要么停更要么不支持咱自己整了个“原生JSSpringBoot”的组合拳——前端用原生File API分片后端用SpringBoot管分片数据库记进度加密用AESSM4类似换库就行。一、前端Vue3 原生JS兼容IE9代码尽量简单老码农看得懂新手能跑通import CryptoJS from crypto-js; // 加密用需npm install crypto-js export default { data() { return { uploading: false, progress: 0, chunkSize: 5 * 1024 * 1024, // 5MB分片20G分4000片 file: null, folderStructure: {}, // 记录文件夹层级 { path/to/file.txt: { size: 1024, chunks: [] } } uploadId: null, // 全局唯一ID断点续传标识 uploadedChunks: new Set() // 已上传分片 }; }, methods: { async handleFileSelect(e) { const files e.target.files; if (!files.length) return; this.file files[0]; // 生成全局唯一uploadId用时间戳随机数 this.uploadId upload_${Date.now()}_${Math.random().toString(36).slice(2, 8)}; // 遍历文件记录文件夹结构兼容IE9用iframe模拟 this.parseFolderStructure(files); // 检查后端已上传分片断点续传关键 await this.checkUploadedChunks(); // 开始上传 this.uploadAllChunks(); }, // 解析文件夹结构兼容IE9 parseFolderStructure(files) { Array.from(files).forEach(file { // IE9不支持webkitRelativePath用FileReader读路径土办法 const reader new FileReader(); reader.onload (e) { const path e.target.result.split(,)[1]; // 实际需用File API获取相对路径IE9用其他方法 this.folderStructure[path] { size: file.size, chunks: [], uploaded: false }; }; reader.readAsDataURL(file); }); }, // 检查已上传分片后端接口 async checkUploadedChunks() { const res await this.$http.get(/api/upload/check?uploadId${this.uploadId}); this.uploadedChunks new Set(res.data.uploadedChunks); // 计算初始进度 this.progress (this.uploadedChunks.size / this.totalChunks) * 100; }, // 上传所有分片控制并发防崩溃 async uploadAllChunks() { this.uploading true; const totalChunks Math.ceil(this.file.size / this.chunkSize); for (let i 0; i totalChunks; i) { if (this.uploadedChunks.has(i)) { this.progress (i / totalChunks) * 100; continue; } const start i * this.chunkSize; const end Math.min(start this.chunkSize, this.file.size); const chunk this.file.slice(start, end); // 加密分片AES密钥从后端获取 const encryptedChunk await this.encryptChunk(chunk); // 构造FormDataIE9用XHRiframe const formData new FormData(); formData.append(file, encryptedChunk, ${this.uploadId}_${i}); formData.append(chunkIndex, i); formData.append(totalChunks, totalChunks); formData.append(uploadId, this.uploadId); formData.append(filePath, this.filePath); // 文件夹路径 try { // 发送请求IE9用xhr const res await this.$http.post(/api/upload/chunk, formData); this.uploadedChunks.add(i); this.progress (i / totalChunks) * 100; } catch (err) { console.error(上传失败:, err); break; } } // 合并分片 if (this.uploadedChunks.size totalChunks) { await this.mergeChunks(); } this.uploading false; }, // 加密分片AES示例 async encryptChunk(chunk) { const key 客户提供的AES密钥16/256位; // 从后端获取更安全 const iv CryptoJS.lib.WordArray.random(16); // 随机IV const encrypted CryptoJS.AES.encrypt( CryptoJS.lib.WordArray.create(chunk), CryptoJS.enc.Utf8.parse(key), { iv: iv } ); return new Blob([iv.toString(), encrypted.toString()], { type: application/octet-stream }); }, // 合并分片触发后端合并 async mergeChunks() { const res await this.$http.post(/api/upload/merge, { uploadId: this.uploadId, fileName: this.file.name, totalChunks: this.totalChunks, filePath: this.filePath }); if (res.code 200) { alert(上传成功); } } } };二、后端SpringBoot分片管理加密存储代码简洁兼容老版本数据库记进度// FileUploadController.java处理上传接口RestControllerRequestMapping(/api/upload)publicclassFileUploadController{Value(${upload.temp.path})privateStringtempPath;// 临时分片存储路径如/data/tempValue(${upload.final.path})privateStringfinalPath;// 最终存储路径如/data/filesAutowiredprivateFileUploadMapperuploadMapper;// MyBatis Mapper操作MySQL// 检查已上传分片GetMapping(/check)publicMapcheckChunks(RequestParamStringuploadId){ListuploadedChunksuploadMapper.selectUploadedChunks(uploadId);MapresnewHashMap();res.put(uploadedChunks,uploadedChunks);returnres;}// 接收分片PostMapping(/chunk)publicMapuploadChunk(RequestParam(file)MultipartFilefile,RequestParamintchunkIndex,RequestParaminttotalChunks,RequestParamStringuploadId,RequestParamStringfilePath){// 创建临时目录StringtempDirtempPath/uploadId;FiledirnewFile(tempDir);if(!dir.exists())dir.mkdirs();// 保存分片加密存储后端解密后存StringchunkPathtempDir/chunkIndex;try{file.transferTo(newFile(chunkPath));}catch(IOExceptione){returnMap.of(code,500,msg,分片保存失败);}// 记录已上传分片到数据库uploadMapper.insertUploadProgress(uploadId,chunkIndex,filePath);returnMap.of(code,200);}// 合并分片PostMapping(/merge)publicMapmergeChunks(RequestParamStringuploadId,RequestParamStringfileName,RequestParaminttotalChunks,RequestParamStringfilePath){StringtempDirtempPath/uploadId;StringfinalFilePathfinalPath/filePath/fileName;// 合并分片解密后合并try(RandomAccessFilerafnewRandomAccessFile(finalFilePath,rw)){for(inti0;itotalChunks;i){StringchunkPathtempDir/i;byte[]chunkDataFiles.readAllBytes(Paths.get(chunkPath));byte[]decryptedDataaesDecrypt(chunkData);// AES解密raf.write(decryptedData);// 删除临时分片Files.delete(Paths.get(chunkPath));}}catch(IOExceptione){returnMap.of(code,500,msg,合并失败);}// 清理数据库记录uploadMapper.deleteUploadProgress(uploadId);returnMap.of(code,200,msg,合并成功);}// AES解密密钥从配置中心获取privatebyte[]aesDecrypt(byte[]data){Stringkey客户提供的AES密钥16/256位;// 实际从配置/数据库获取// 解密逻辑略用AES/CBC/PKCS5PaddingreturndecryptedData;}}// FileUploadMapper.javaMyBatis操作数据库publicinterfaceFileUploadMapper{Select(SELECT chunk_index FROM file_upload_progress WHERE upload_id #{uploadId})ListselectUploadedChunks(Param(uploadId)StringuploadId);Insert(INSERT INTO file_upload_progress (upload_id, chunk_index, file_path) VALUES (#{uploadId}, #{chunkIndex}, #{filePath}) ON DUPLICATE KEY UPDATE chunk_index #{chunkIndex})voidinsertUploadProgress(Param(uploadId)StringuploadId,Param(chunkIndex)intchunkIndex,Param(filePath)StringfilePath);Delete(DELETE FROM file_upload_progress WHERE upload_id #{uploadId})voiddeleteUploadProgress(Param(uploadId)StringuploadId);}三、数据库表结构MySQLCREATETABLEfile_upload_progress(idINTPRIMARYKEYAUTO_INCREMENT,upload_idVARCHAR(64)NOTNULLCOMMENT全局上传ID,chunk_indexINTNOTNULLCOMMENT分片序号,file_pathVARCHAR(255)NOTNULLCOMMENT文件/文件夹路径,UNIQUEKEYuk_upload_chunk(upload_id,chunk_index)-- 唯一索引防重复);咱的“保姆级”支持预算有限但服务到位代码完整提供前端Vue3组件含IE9兼容补丁、后端SpringBoot代码含MyBatis配置、数据库脚本解压就能跑。部署简单写了一键打包脚本npm run buildmvn packageTomcat直接扔WAR包MySQL导入SQL就行。加密支持AES密钥可配置客户自己保管SM4换库就能用附BouncyCastle集成文档。兼容兜底IE9用iframe模拟上传代码里标了注释现代浏览器用原生Fetch主流浏览器全支持。最后唠唠接单群资源分享咱建了个QQ群374992201专门拉“外包码农”和“找项目的老板”——群里福利拉满新人加群送1~99元红包手慢无推荐项目拿20%提成2万项目提4千比外卖自由香多了技术交流大文件上传、加密、兼容问题随便问老码农在线答疑内推工作福州IT圈岗位大厂外包都有。咱这项目要是成了答辩老师看了都得夸“这程序员有点东西” 赶紧加群一起搞钱一起秃一起当“外包大佬”PS群里还有人分享“如何用AI写文档”的玄学技巧亲测能过甲方审核导入项目导入到Eclipse点南查看教程导入到IDEA点击查看教程springboot统一配置点击查看教程工程NOSQLNOSQL示例不需要任何配置可以直接访问测试创建数据表选择对应的数据表脚本这里以SQL为例修改数据库连接信息访问页面进行测试文件存储路径up6/upload/年/月/日/guid/filename效果预览文件上传文件刷新续传支持离线保存文件进度在关闭浏览器刷新浏览器后进行不丢失仍然能够继续上传文件夹上传支持上传文件夹并保留层级结构同样支持进度信息离线保存刷新页面关闭页面重启系统不丢失上传进度。下载示例点击下载完整示例
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

北京专业建设网站公司成成品网站源码有限公司

EmotiVoice 是否支持语音情感随机扰动?增强自然感功能 在虚拟助手越来越频繁地进入我们生活的今天,一个关键问题浮出水面:为什么有些AI语音听起来依然像“复读机”,而另一些却仿佛真人在说话?答案往往不在于发音是否清…

张小明 2025/12/19 16:43:09 网站建设

好看的免费网站模板下载wordpress对联

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

张小明 2025/12/19 16:42:08 网站建设

五屏网站建设哪家有网站开发需要会什么

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 快速创建一个安卓开发概念验证原型,展示核心功能和用户体验。点击项目生成按钮,等待项目生成完整后预览效果 最近想尝试一个安卓应用的新功能点子&#xff0…

张小明 2025/12/19 16:41:06 网站建设

中山网站方案宁波seo服务推广软件

在Ubuntu系统中查询显卡的生产日期,最核心且可靠的方法是找到显卡上的SN码(序列号),然后通过特定规则解读或官网查询。由于Ubuntu没有像Windows那样直接显示生产日期的图形化工具,命令行也无法直接获取此信息&#xff…

张小明 2025/12/19 16:40:05 网站建设

怎么用div布局做网站西安做网站 送百度首页

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个面向新手的Nginx命令交互式学习应用,功能包括:1) 分步骤动画演示命令执行过程 2) 安全沙箱环境供实操练习 3) 常见错误模拟与解决方法 4) 渐进式学习…

张小明 2025/12/19 16:39:04 网站建设

河北网站建设多少钱wordpress 订单系统

Docker进阶:从任务管理到高级配置 容器资源与任务管理 容器实例的输出信息包含了已注册资源和剩余资源。在多实例的情况下,这些信息能帮助服务决定在集群中部署容器的位置。 当容器集群启动并运行后,就需要创建至少一个任务定义。任务定义指的是将一组容器组合在一起。以…

张小明 2025/12/19 16:37:02 网站建设