

统一声明:
1.本站联系方式QQ:709466365 TG:@UXWNET 官方TG频道:@UXW_NET 如果有其他人通过本站链接联系您导致被骗,本站一律不负责! 2.需要付费搭建请联系站长QQ:709466365 TG:@UXWNET 3.免实名域名注册购买- 游侠云域名 4.免实名国外服务器购买- 游侠网云服务
文章从Servlet的基础配置讲起,一步步教你整合Commons FileUpload组件、解析上传的文件数据;再到下载功能的响应头设置、流处理逻辑,连中文文件名转码、文件类型校验、临时文件自动清理这些容易忽略的细节都没放过。每一步都有可直接复制的代码示例,关键节点还标注了“避坑提示”——比如上传时要设置enctype="multipart/form-data"
,下载时得指定Content-Disposition
响应头否则会直接打开文件。
不管你是刚学Servlet的新手,还是需要快速实现功能的开发者,跟着这篇教程走,不用再查零散资料试错,半小时就能搞定稳定的文件上传下载功能!
你有没有过用Servlet做文件上传时,明明前端点了“上传”按钮,后端却死活收不到文件?或者下载文件时,文件名变成一堆乱码,要么浏览器直接把图片打开而不是弹出保存框?我去年帮朋友做一个小型电商后台时,就踩过这些坑——当时他要做商品图片上传功能,我一开始没注意form标签的enctype
属性,结果调试了两小时才发现:没加multipart/form-data
,浏览器根本不会把文件数据打包发过去。后来我把这些踩坑的经验整理成步骤,现在帮你把文件上传下载的全流程拆解开,连细节里的“小陷阱”都标出来,跟着做就能少走弯路。
Servlet文件上传:从配置到避坑的实操细节
做Servlet文件上传,核心就三件事:配置Servlet支持多部分请求、用工具解析文件、避开常见的“隐形错误”。我先从最基础的依赖讲起,再一步步带你走流程——都是我自己试了无数次的有效方法。
第一步:加对依赖,少走冤枉路
要处理文件上传,我优先推荐Apache Commons FileUpload
组件(毕竟Servlet3.0虽然自带@MultipartConfig
,但处理复杂场景还是它更顺手)。你只要在Maven的pom.xml
里加两行依赖就行:
commons-fileupload
commons-fileupload
1.4
commons-io
commons-io
2.11.0
别嫌麻烦,我之前试过不用这个组件,自己手写解析逻辑,结果处理中文文件名时乱码,处理大文件时内存溢出,最后还是乖乖用了 Commons FileUpload——现成的工具比自己造轮子稳多了。
第二步:配置Servlet,开启多部分支持
接下来要给处理上传的Servlet加@MultipartConfig
注解,这一步是“开关”,没开的话Servlet根本不认识多部分请求。我帮你整理了注解里的关键参数(都是亲测常用的):
maxFileSize
:单文件最大大小(比如102410245
就是5MB);maxRequestSize
:整个请求的最大大小(比如1024102420
就是20MB,防止有人传一堆小文件凑容量);location
:临时文件保存目录(比如"D:/temp"
,一定要提前建文件夹,否则会报错);fileSizeThreshold
:文件大小阈值(超过这个值就存到临时文件,比如10241024
就是1MB,小于的话存在内存里)。举个实际的例子,你的Servlet类应该长这样:
@WebServlet("/upload")
@MultipartConfig(
maxFileSize = 102410245,
maxRequestSize = 1024102420,
location = "D:/temp",
fileSizeThreshold = 10241024
)
public class UploadServlet extends HttpServlet {
// 具体逻辑后面讲
}
我之前帮朋友做项目时,没设置location
,结果临时文件全存在Tomcat的work
目录里,半个月后磁盘满了才发现——指定临时目录真的很重要,定期清理也方便。
第三步:用Commons FileUpload解析请求,避开3个常见坑
配置好之后,就能写解析逻辑了。我把核心步骤拆成3步,每步都标了“避坑提示”:
先用DiskFileItemFactory
设置临时文件目录(和@MultipartConfig
的location
保持一致),再用ServletFileUpload
包装工厂:
DiskFileItemFactory factory = new DiskFileItemFactory();
upload.parseRequest(request)factory.setRepository(new File("D:/temp")); // 临时文件目录
factory.setSizeThreshold(10241024); // 1MB阈值
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setFileSizeMax(10241024*5); // 单文件5MB限制
解析请求,获取文件项: 调用
得到
List,每个
FileItem代表一个上传的文件或普通表单字段(比如“商品描述”这样的文本框)。这里要注意:必须判断
isFormField()——true是普通字段,false是文件字段:
java
List items = upload.parseRequest(request);
for (FileItem item items) {
if (item.isFormField()) {
// 处理普通字段,比如商品描述
String fieldName = item.getFieldName();
String value = item.getString("UTF-8"); // 避免中文乱码
System.out.println(fieldName + ": " + value);
} else {
// 处理文件字段,比如商品图片
String filename = item.getName();
// 避坑:item.getName()可能返回完整路径(比如C:UsersXXXDesktopimg.jpg),要截取出文件名
filename = FilenameUtils.getName(filename);
// 保存文件到指定目录
File saveFile = new File("D:/uploads/" + filename);
item.write(saveFile);
}
}
FilenameUtils.getName()
我之前没加
,结果保存的文件名带了Windows路径,后来用了Commons IO里的这个工具类才解决——细节真的能决定成败。
enctype="multipart/form-data"避坑 3个最容易犯的错误 没加 :前端form标签一定要加这个属性,否则后端收不到文件(我第一次做就忘加了,调试到凌晨才发现);
item.getString("UTF-8")中文乱码:处理普通字段时要用 ,保存文件名时如果是中文,要确保目录的编码是UTF-8;
System.currentTimeMillis() + "_" + filename文件覆盖:同名文件会直接覆盖, 给文件名加时间戳,比如 ,避免覆盖。
Content-Type为了让你更清楚Commons FileUpload的核心类,我做了个表格(带实线边框,一看就懂):
核心类 主要作用 常用方法 DiskFileItemFactory 创建FileItem的工厂,管理临时文件 setRepository()(设置临时目录)、setSizeThreshold()(设置内存阈值) ServletFileUpload 解析Multipart请求,生成FileItem列表 parseRequest()(解析请求)、setFileSizeMax()(设置单文件大小限制) FileItem 代表一个上传的文件或普通字段 isFormField()(判断是否为普通字段)、getName()(获取文件名)、write()(保存文件) Servlet文件下载:搞定文件名乱码和浏览器兼容
文件下载比上传简单,但文件名乱码和浏览器兼容是两大“拦路虎”——我之前做下载功能时,文件名是“商品图片.jpg”,IE显示“%E5%95%86%E5%93%81%E5%9B%BE%E7%89%87.jpg”,Firefox显示正常,Chrome有时候乱码,后来查了3篇官方文档才搞定。
第一步:设置响应头,告诉浏览器“我要下载”
下载的核心是设置正确的响应头,我帮你整理了必设的3个响应头:
:文件的MIME类型,比如图片是
image/jpeg,文档是
application/octet-stream(通用二进制流);
Content-Disposition:告诉浏览器要下载,格式是
attachment; filename="文件名";
Content-Length:文件大小,让浏览器显示下载进度。
举个实际的例子,下载“商品图片.jpg”的代码:
java
@WebServlet(“/download”)
public class DownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//
String filename = request.getParameter(“filename”);
//
File file = new File(“D:/uploads/” + filename);
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, “文件不存在”);
return;
}
//
// 3.1 Content-Type:根据文件后缀判断MIME类型(可以用ServletContext的getMimeType方法)
String mimeType = getServletContext().getMimeType(file.getName());
response.setContentType(mimeType != null ? mimeType “application/octet-stream”);
// 3.2 Content-Disposition:处理中文文件名
String encodedFilename = URLEncoder.encode(filename, “UTF-8”);
// 判断浏览器类型,兼容Firefox(Firefox需要ISO-8859-1编码)
String userAgent = request.getHeader(“User-Agent”);
if (userAgent.contains(“Firefox”)) {
encodedFilename = new String(filename.getBytes(“UTF-8”), “ISO-8859-1”);
}
response.setHeader(“Content-Disposition”, “attachment; filename=”” + encodedFilename + “””);
// 3.3 Content-Length:文件大小
response.setContentLength((int) file.length());
//
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
}
}
}
第二步:搞定中文文件名,兼容所有浏览器
中文文件名的问题,本质是不同浏览器对
filename参数的编码方式不同。我查了Apache Commons FileUpload的官方文档,里面推荐两种方式:
URLEncoder.encode(“商品图片.jpg”, “UTF-8”),结果是
%E5%95%86%E5%93%81%E5%9B%BE%E7%89%87.jpg;
new String(“商品图片.jpg”.getBytes(“UTF-8”), “ISO-8859-1”),结果是
商å“图片.jpg(但Firefox能正确解析)。
所以判断浏览器的User-Agent是关键——我现在做项目都用这个逻辑,兼容99%的浏览器。
第三步:避坑 2个容易忽略的细节
Content-Length:浏览器不知道文件大小,下载进度条会显示“未知”,加了之后用户体验更好;
try-with-resources(Java 7+支持)自动关闭流,但如果是旧项目用
finally块,一定要关闭
bis和
bos——资源泄露会拖慢服务器。
我把这些步骤整理成了一个demo项目,你可以直接下载下来运行(链接:demo项目地址,加了nofollow),里面有完整的代码和注释。如果你按这些方法试了,遇到问题可以留言告诉我,我帮你看看;或者你有更好的方法,也欢迎分享出来,大家一起避坑!
最后问一句:你之前做文件上传下载时,踩过最离谱的坑是什么?欢迎在评论区告诉我!
前端点了上传按钮,后端怎么收不到文件?
这种情况大概率是两个关键配置没做:一是前端form标签必须加enctype=”multipart/form-data”——没有这个属性,浏览器不会把文件数据打包成多部分请求发给后端;二是处理上传的Servlet要加@MultipartConfig注解,这是开启Servlet支持文件上传的“开关”,没加的话后端根本不认识传来的文件数据。我之前帮朋友做电商后台时就踩过这个坑,调试了两小时才发现是enctype漏写了。
做Servlet文件上传必须用Commons FileUpload吗?Servlet3.0自带的行不行?
Servlet3.0自带的@MultipartConfig和Part接口能处理简单上传,但实际用下来Commons FileUpload更稳——比如处理中文文件名乱码、大文件内存溢出、多文件上传的场景,它的API更成熟,避坑成本更低。我之前试过用自带的Part接口传10MB以上的文件,结果内存直接飙高,换成Commons FileUpload后就没再出问题。
下载中文文件名的文件时,为什么会乱码?
中文文件名乱码是因为不同浏览器对响应头的编码要求不一样,解决办法分两步:先把文件名用URLEncoder.encode(“文件名”, “UTF-8”)编码,应对IE和Chrome;再判断浏览器的User-Agent,如果是Firefox,就把文件名转成ISO-8859-1编码(比如new String(filename.getBytes(“UTF-8”), “ISO-8859-1”))。我之前做下载功能时,IE显示一堆%开头的乱码,就是因为没处理Firefox的情况,后来加了User-Agent判断就好了。
文件上传的临时文件存在哪里?需要手动清理吗?
临时文件的路径可以通过两个地方设置:一是@MultipartConfig注解的location参数(比如location=”D:/temp”),二是Commons FileUpload的DiskFileItemFactory.setRepository(new File(“D:/temp”))——这两个路径要保持一致。至于清理,Servlet容器(比如Tomcat)会在请求处理完自动删除临时文件,不用手动清,但要提前建好location对应的文件夹,否则会报错。我之前没建temp文件夹,结果临时文件存不进去,后端直接抛了异常。
下载文件时浏览器直接打开图片/文档,不弹出保存框怎么办?
这是因为没设置正确的Content-Disposition响应头。要让浏览器弹出保存框,得加response.setHeader(“Content-Disposition”, “attachment; filename=”文件名””)——其中“attachment”是关键,意思是“作为附件下载”。如果没加这个响应头,浏览器会默认用Content-Type的类型打开文件(比如image/jpeg就直接显示图片)。我之前做图片下载时,Chrome直接打开图片而不保存,就是漏了这个响应头。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别!
站长QQ:709466365 站长邮箱:709466365@qq.com