news 2026/4/26 11:51:03

JAVA如何高效实现http大文件上传?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JAVA如何高效实现http大文件上传?

大文件上传系统开发指南(基于原生JS+SpringBoot)

项目背景

老哥我最近接了个"硬骨头"项目,客户要求实现20G大文件上传下载,还要支持文件夹结构保留、加密传输、断点续传,还要兼容IE9这种古董浏览器。预算只有100块,还要7×24小时技术支持…这活儿简直比相亲还难!

不过没关系,谁让我进了这个"坑"呢?下面我就把这段时间折腾出来的代码和经验分享给大家,希望能帮到同样在"水深火热"中的同行们。

技术选型

  • 前端:Vue3 CLI + 原生JavaScript(客户要求必须用原生JS实现上传核心功能)
  • 后端:SpringBoot + Tomcat
  • 数据库:MySQL(主要存用户信息和文件元数据)
  • 文件存储:直接服务器存储(简单粗暴,符合预算)
  • 加密:SM4(国密)和AES双支持

系统架构

浏览器(IE9+等) ←HTTP/HTTPS→ SpringBoot后端 ←本地文件IO→ 服务器存储 ↑ MySQL

前端实现(Vue3 + 原生JS上传核心)

1. 文件选择组件(支持文件夹)

export default { data() { return { fileList: [], isUploading: false, progress: 0, chunkSize: 5 * 1024 * 1024, // 5MB每片 currentUploads: {} } }, methods: { triggerFileInput() { document.getElementById('fileInput').click(); }, handleFileChange(e) { const files = Array.from(e.target.files); if (files.length === 0) return; // 处理文件夹结构 const fileTree = {}; files.forEach(file => { const path = file.webkitRelativePath || file.name; this.fileList.push({ file: file, relativePath: path, size: file.size, chunks: Math.ceil(file.size / this.chunkSize), uploadedChunks: 0 }); }); }, } }

后端实现(SpringBoot)

1. 文件上传控制器

// src/main/java/com/example/uploader/controller/FileUploadController.javapackagecom.example.uploader.controller;@RestController@RequestMapping("/api")publicclassFileUploadController{@Value("${file.upload-dir}")privateStringuploadDir;// 存储上传进度信息(实际项目应该用数据库)privatefinalMapprogressMap=newConcurrentHashMap<>();@PostMapping("/upload")publicMaphandleFileUpload(@RequestParam("file")MultipartFilefile,@RequestParam("relativePath")StringrelativePath,@RequestParam("totalChunks")inttotalChunks,@RequestParam("currentChunk")intcurrentChunk,@RequestParam("fileSize")longfileSize,@RequestParam("fileMd5")StringfileMd5,HttpServletRequestrequest)throwsIOException{Mapresult=newHashMap<>();try{// 创建文件存储目录(保留文件夹结构)PathfilePath=Paths.get(uploadDir,relativePath);Files.createDirectories(filePath.getParent());// 如果是加密上传,这里应该先解密(示例省略)// 以追加模式写入文件块try(RandomAccessFilerandomAccessFile=newRandomAccessFile(filePath.toFile(),"rw")){randomAccessFile.seek((long)currentChunk*5*1024*1024);// 5MB每块randomAccessFile.write(file.getBytes());}// 更新上传进度UploadProgressprogress=progressMap.computeIfAbsent(fileMd5,k->newUploadProgress(fileMd5,relativePath,fileSize,totalChunks));progress.markChunkUploaded(currentChunk);// 如果是最后一块,清理进度信息if(progress.isComplete()){progressMap.remove(fileMd5);// 这里可以触发文件后处理,如加密存储等}result.put("success",true);result.put("message","Chunk uploaded successfully");result.put("uploadedChunks",progress.getUploadedChunks());}catch(Exceptione){result.put("success",false);result.put("message","Upload failed: "+e.getMessage());}returnresult;}}

2. 文件下载控制器

// src/main/java/com/example/uploader/controller/FileDownloadController.java@RestController@RequestMapping("/api")publicclassFileDownloadController{@Value("${file.upload-dir}")privateStringuploadDir;@GetMapping("/download")publicResponseEntitydownloadFile(@RequestParamStringrelativePath,HttpServletRequestrequest)throwsIOException{PathfilePath=Paths.get(uploadDir,relativePath).normalize();Resourceresource=newUrlResource(filePath.toUri());if(!resource.exists()){returnResponseEntity.notFound().build();}// 确定内容类型StringcontentType=request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());if(contentType==null){contentType="application/octet-stream";}returnResponseEntity.ok().contentType(MediaType.parseMediaType(contentType)).header(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=\""+filePath.getFileName()+"\"").body(resource);}}

3. 加密工具类(简化版)

// src/main/java/com/example/uploader/util/CryptoUtil.javapackagecom.example.uploader.util;importjavax.crypto.Cipher;importjavax.crypto.spec.SecretKeySpec;importjava.util.Base64;publicclassCryptoUtil{privatestaticfinalStringAES="AES";// 实际项目应该从安全配置中获取密钥privatestaticfinalbyte[]AES_KEY="ThisIsASecretKey1234567890".getBytes();// 16/24/32字节publicstaticbyte[]encryptAES(byte[]data)throwsException{SecretKeySpeckeySpec=newSecretKeySpec(AES_KEY,AES);Ciphercipher=Cipher.getInstance(AES);cipher.init(Cipher.ENCRYPT_MODE,keySpec);returncipher.doFinal(data);}}

配置文件

application.properties

# 文件上传目录(确保应用有写入权限) file.upload-dir=./uploads # Spring Boot默认配置 server.port=8080 spring.servlet.multipart.max-file-size=10GB spring.servlet.multipart.max-request-size=10GB # 数据库配置(如果需要) spring.datasource.url=jdbc:mysql://localhost:3306/uploader?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

部署说明

  1. 环境准备

    • JDK 8+
    • Maven
    • Node.js (用于前端开发)
    • MySQL (可选,如果需要数据库)
  2. 构建前端

    cdfrontendnpminstallnpmrun build
  3. 构建后端

    mvn clean package
  4. 部署

    • 将前端构建产物(dist目录)复制到SpringBoot的src/main/resources/static目录
    • 运行SpringBoot应用:
      java -jar target/uploader-0.0.1-SNAPSHOT.jar
  5. Nginx配置(可选)
    如果需要处理大文件上传,建议使用Nginx反向代理:

    server { listen 80; server_name yourdomain.com; client_max_body_size 21G; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

兼容性处理

IE9兼容性方案

由于IE9不支持FormDataFile API的某些特性,我们需要做特殊处理:

  1. 前端修改
// 在FileUploader.vue中添加IE9兼容代码methods:{handleFileChange(e){constfiles=e.target.files;if(!files){// IE9兼容处理this.handleIE9FileSelect();return;}// 原有代码...},}
  1. 后端调整

对于IE9的上传请求,可能需要使用传统的multipart/form-data方式而非分块上传。

加密传输实现

如果需要端到端加密,可以在前端加密后上传:

// 在uploadFile方法中添加加密处理asyncuploadFile(fileItem){// ...之前的代码constchunk=file.slice(start,end);letencryptedChunk=chunk;// 根据配置选择加密方式if(this.encryptType==='AES'){encryptedChunk=awaitthis.encryptAES(chunk);}elseif(this.encryptType==='SM4'){encryptedChunk=awaitthis.encryptSM4(chunk);}constformData=newFormData();formData.append('file',newBlob([encryptedChunk]));// ...其他参数// ...上传代码},

性能优化建议

  1. 分块大小调整:根据网络情况动态调整分块大小(5MB-20MB之间)
  2. 并发控制:根据用户带宽和设备性能调整并发上传数
  3. Web Worker:将哈希计算和加密操作放到Web Worker中,避免阻塞UI
  4. 本地缓存:使用IndexedDB缓存已计算的哈希值
  5. 心跳机制:定期向服务器发送心跳,维护上传会话

完整项目结构

file-uploader/ ├── frontend/ # Vue3前端 │ ├── src/ │ │ ├── components/ │ │ │ └── FileUploader.vue │ │ ├── App.vue │ │ └── main.js │ ├── package.json │ └── vue.config.js ├── backend/ # SpringBoot后端 │ ├── src/ │ │ ├── main/ │ │ │ ├── java/com/example/uploader/ │ │ │ │ ├── controller/ │ │ │ │ ├── util/ │ │ │ │ └── Application.java │ │ │ └── resources/ │ │ │ └── application.properties │ └── pom.xml ├── uploads/ # 文件存储目录(自动创建) ├── nginx.conf # Nginx配置示例 └── README.md # 项目说明

总结

这个项目确实是个挑战,特别是在100元预算和兼容IE9的双重限制下。不过通过分块上传、断点续传和合理的架构设计,我们还是能够实现客户的需求。

关键点总结:

  1. 前端使用原生JS实现核心上传逻辑,Vue3负责UI和状态管理
  2. 后端SpringBoot处理文件存储和进度跟踪
  3. 分块上传+本地缓存实现断点续传
  4. 保留完整的文件夹结构
  5. 通过Nginx处理大文件上传

实际项目中,你可能还需要:

  • 添加用户认证
  • 实现更完善的错误处理和重试机制
  • 添加文件预览功能
  • 实现更安全的加密方案
  • 添加管理员界面

希望这个示例能帮到你,也欢迎加入我们的QQ群(374992201)一起交流技术、合作项目。群里定期有技术分享和红包活动,还有项目合作机会哦!

最后提醒一句:这种预算的项目,记得在合同里明确需求范围和变更条款,不然很容易亏本哦!

导入项目

导入到Eclipse:点南查看教程
导入到IDEA:点击查看教程
springboot统一配置:点击查看教程

工程

NOSQL

NOSQL示例不需要任何配置,可以直接访问测试

创建数据表

选择对应的数据表脚本,这里以SQL为例

修改数据库连接信息

访问页面进行测试

文件存储路径

up6/upload/年/月/日/guid/filename

效果预览

文件上传

文件刷新续传

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

文件夹上传

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

下载示例

点击下载完整示例

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

亲测好用 8个AI论文网站:研究生毕业论文写作与格式规范全测评

在当前学术研究日益数字化的背景下&#xff0c;研究生群体面临着论文写作、文献检索、格式规范等多重挑战。尤其是在AI技术广泛应用的今天&#xff0c;如何选择一款高效、专业且符合学术规范的写作工具&#xff0c;成为许多学生关注的焦点。为了帮助广大研究生更科学地挑选适合…

作者头像 李华
网站建设 2026/4/24 16:25:12

Deepoc数学大模型:赋能半导体产业,破解研发与量产核心痛点

半导体工艺向3nm及以下先进节点迭代过程中&#xff0c;芯片设计复杂度、制造精度呈几何级攀升&#xff0c;研发周期冗长、试错成本高企、高端EDA工具掣肘、量产良率难管控等行业痛点日益凸显&#xff0c;严重制约产业高质量发展。传统半导体产业以工程师经验为核心驱动&#xf…

作者头像 李华
网站建设 2026/4/13 2:27:33

计算机毕业设计springboot大学生社会实践信息管理系统 基于SpringBoot的高校社会实践活动全周期管理平台 基于SpringBoot的大学生校外实践教学信息化服务平台

计算机毕业设计springboot大学生社会实践信息管理系统0zank987 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。在高等教育深化改革的背景下&#xff0c;社会实践活动已成为培养学…

作者头像 李华
网站建设 2026/4/21 7:49:42

LangChain十年演进

LangChain 的十年&#xff08;2015–2025&#xff09;&#xff0c;是一段从“不存在”到“爆发式流行”&#xff0c;再到“通过 LangGraph 深度重塑 Agent 逻辑”&#xff0c;最后在 2025 年演进为“云原生、内核级编排的 AI 操作系统驱动程序”的激荡史。 虽然 LangChain 诞生…

作者头像 李华
网站建设 2026/4/26 9:55:28

好写作AI:再也不用“好像/可能/大概”了!学术语言变身指南

导语&#xff1a;每个深夜的文档前&#xff0c;都有个被表达“榨干”的灵魂 写论文时&#xff0c;你是否经历过这样的“精神分裂”&#xff1f;脑海里思如泉涌&#xff0c;指尖输出的文字却像“小学生作文”&#xff1b;明明数据扎实、观点新颖&#xff0c;写出来却总觉得“差…

作者头像 李华