JSP 文件上传
multipart 表单、Part 读取、保存路径与安全校验。
表单
<form action="upload.jsp" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="text" name="note" placeholder="说明">
<button>上传</button>
</form>Of the three enctype values only multipart/form-data sends file bytes; the default application/x-www-form-urlencoded sends just the name.
接收
<%@ page contentType="text/html;charset=UTF-8"
import="java.io.*, java.nio.file.*, java.util.UUID" %>
<%
request.setCharacterEncoding("UTF-8");
Part part = request.getPart("file");
String name = part.getSubmittedFileName();
if (name == null || name.isBlank()) {
out.println("<p>没有选择文件</p>");
return;
}
String ext = name.substring(name.lastIndexOf('.')).toLowerCase();
if (!java.util.Set.of(".jpg", ".png", ".pdf").contains(ext)) {
response.sendError(400, "不支持的文件类型");
return;
}
Path dir = Path.of(application.getRealPath("/uploads"));
Files.createDirectories(dir);
Path target = dir.resolve(UUID.randomUUID() + ext);
part.write(target.toString());
out.println("<p>已保存:" + target.getFileName() + "</p>");
%>已保存:3f9c1b2a-7d4e-4c88-a1b0-6e2d5f7a8c91.pdf配置大小限制
<servlet>
<servlet-name>upload</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<multipart-config>
<max-file-size>5242880</max-file-size> <!-- 5MB -->
<max-request-size>20971520</max-request-size> <!-- 20MB -->
<file-size-threshold>1048576</file-size-threshold>
</multipart-config>
</servlet>A JSP cannot use the @MultipartConfig annotation (that is for servlets). Either declare multipart-config in web.xml or move the upload into a servlet and use the JSP only for display — the latter is cleaner.
三条安全规则
- 重命名 —— 原文件名可能是
../../web.xml,直接用会覆盖任意文件 - 白名单扩展名 —— 黑名单永远漏,只允许明确需要的类型
- 别放在能执行脚本的目录 —— 上传目录能跑 JSP 就等于开了后门
application.getRealPath() returns null when the war is not exploded. In production store files outside the web root (e.g. /data/uploads) and serve them through a download servlet — which also gives you access control.大文件
Part.write() stages the whole file in a temp directory, doubling disk for GB uploads. Use a streaming parser (Commons FileUpload Streaming API) to read and write in chunks.
表单
<form action="upload.jsp" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="text" name="note" placeholder="说明">
<button>上传</button>
</form>enctype 三个值里只有 multipart/form-data 会传文件内容,默认的 application/x-www-form-urlencoded 只传文件名。
接收
<%@ page contentType="text/html;charset=UTF-8"
import="java.io.*, java.nio.file.*, java.util.UUID" %>
<%
request.setCharacterEncoding("UTF-8");
Part part = request.getPart("file");
String name = part.getSubmittedFileName();
if (name == null || name.isBlank()) {
out.println("<p>没有选择文件</p>");
return;
}
String ext = name.substring(name.lastIndexOf('.')).toLowerCase();
if (!java.util.Set.of(".jpg", ".png", ".pdf").contains(ext)) {
response.sendError(400, "不支持的文件类型");
return;
}
Path dir = Path.of(application.getRealPath("/uploads"));
Files.createDirectories(dir);
Path target = dir.resolve(UUID.randomUUID() + ext);
part.write(target.toString());
out.println("<p>已保存:" + target.getFileName() + "</p>");
%>已保存:3f9c1b2a-7d4e-4c88-a1b0-6e2d5f7a8c91.pdf配置大小限制
<servlet>
<servlet-name>upload</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<multipart-config>
<max-file-size>5242880</max-file-size> <!-- 5MB -->
<max-request-size>20971520</max-request-size> <!-- 20MB -->
<file-size-threshold>1048576</file-size-threshold>
</multipart-config>
</servlet>JSP 没有 @MultipartConfig 注解可用(那是给 Servlet 的),要么在 web.xml 里配 multipart-config,要么把上传逻辑挪到一个 Servlet 里再用 JSP 显示结果——后者更清晰。
三条安全规则
- 重命名 —— 原文件名可能是
../../web.xml,直接用会覆盖任意文件 - 白名单扩展名 —— 黑名单永远漏,只允许明确需要的类型
- 别放在能执行脚本的目录 —— 上传目录能跑 JSP 就等于开了后门
application.getRealPath() 在 war 包未解压时返回 null。生产环境应该把文件存到 Web 根之外的固定目录(如 /data/uploads),再用一个下载 Servlet 读出来——顺便还能做权限控制。大文件
Part.write() 先把整个文件落到临时目录,GB 级文件要占双倍磁盘。超大文件应改用流式解析(Commons FileUpload 的 Streaming API),边读边写。