java如何上传文件:三种主流实现
java如何上传文件这件事,在Servlet3.0之后已经不需要再引入第三方包。你可以直接用HttpServletRequest.getParts()接收二进制流,也可以用SpringMVC封装好的MultipartFile对象,或者在SSM老项目里继续用ApacheCommonsFileUpload。三种方式底层都是把multipart/form-data请求体拆成表单字段和文件块,区别只在API封装层。文件小于10MB、单请求单文件的常规后台场景,SpringMVC的MultipartFile写法相对简洁;需要脱离Web框架、做嵌入式Servlet或者纯Servlet项目时,原生Part接口逻辑更直接;只有还在跑Servlet2.5的老系统才需要CommonsFileUpload。生产环境必须配的两个硬参数是单文件大小上限和总请求大小上限,SpringBoot下默认值分别是1MB和10MB,不调整直接传超过1MB的图片会直接抛MaxUploadSizeExceededException。
java上传文件的三种方式对比
| 实现方式 | 适用框架 | 关键API | 是否需要额外依赖 |
|---|---|---|---|
| Servlet3.0原生Part | 任何Servlet容器 | request.getParts() | 不需要 |
| SpringMVCMultipartFile | Spring3.1+/SpringBoot | MultipartFile.transferTo() | 不需要 |
| ApacheCommonsFileUpload | Servlet2.5老项目 | FileItemFactory | 需要commons-fileupload包 |
SpringMVC方式的核心代码就一行:控制器方法参数声明MultipartFilefile,框架会自动把对应name的文件绑定进来。拿到对象后调用file.transferTo(newFile("D:/upload/"+file.getOriginalFilename()))完成落盘。SpringBoot项目不需要再配置MultipartResolver,因为内嵌Tomcat已经启用了标准Servlet文件上传,只需要在application.properties里写spring.servlet.multipart.max-file-size=10MB和spring.servlet.multipart.max-request-size=50MB就能改上限。
原生Part方式要在Servlet上加@MultipartConfig注解,里面配fileSizeThreshold、location、maxFileSize、maxRequestSize四个参数。接收时遍历request.getParts(),每个Part通过part.getInputStream()读流,用part.getSubmittedFileName()拿原始文件名。这种写法在Spring环境里反而绕,因为Spring会优先接管Part解析,重复读取容易出现流已关闭异常。
文件名安全处理不能省。直接把file.getOriginalFilename()拼到存储路径后面,攻击者可以构造../../etc/passwd这类路径穿越字符串,把文件写到Web容器目录之外。正确做法是用newFile(uploadDir,UUID.randomUUID().toString())生成新文件名,原始文件名只存数据库字段里做展示。
大文件必须分片。
超过50MB的单文件如果还走单请求上传,网络一抖就要整段重传。前端按5MB一片切分,每片带chunkNumber和totalChunks参数发到后端,后端用RandomAccessFile按位置合并。这个方案在Servlet3.0和SpringMVC下都能跑,不需要额外组件。
ApacheCommonsFileUpload在Servlet3.0规范发布后已经不推荐新项目使用。JSR315规范2009年就把文件上传写进了标准API,Tomcat7及以上版本原生支持,继续引commons-fileupload-1.4.jar只是增加依赖树体积。老项目迁移时把org.apache.commons.fileupload.servlet.ServletFileUpload换成Part接口,解析逻辑基本一一对应。
该方法的适用边界是:单次请求只接收文件本体,不接收JSON体。因为multipart/form-data和application/json是两种Content-Type,同一个接口不能既收JSON对象又收文件,必须把JSON字段改成表单字段或者单独走两次请求。上传目录要放在Web应用外部,不要放进WEB-INF同级的静态资源目录,否则用户通过URL直接访问上传的.html文件会触发存储型XSS。
配置完之后用Postman选form-data、key类型切到File发一个测试请求,控制台能打印出文件名和字节数,再去目标目录确认文件落盘,这两步走通才算真正接通。
