"JSP+Servlet实现文件上传下载",基本上可以分为文件上传和文件下载两个部分。下面详细讲解一下文件上传部分的实现过程。
文件上传实现
1. 文件上传表单页面
首先需要在页面上提供上传文件的表单。代码如下:
<form action="upload" method="post" enctype="multipart/form-data">
请选择要上传的文件:<input type="file" name="file"><br/>
<input type="submit" value="上传">
</form>
这个表单中,注意以下三点:
- action 属性设为 "upload",表示文件上传的处理器的 url-pattern 属性值。
- method 属性设为 "post",因为上传的文件可能比较大,需要使用 POST 方法上传。
- enctype 属性设为 "multipart/form-data",表示 form 内容包含二进制数据。
2. 文件上传处理器
然后在 Servlet 中写文件上传处理器:
@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 检查是否为 multipart/form-data 表单
if (!ServletFileUpload.isMultipartContent(req)) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Not a multipart request.");
return;
}
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload uploader = new ServletFileUpload(factory);
uploader.setFileSizeMax(1024 * 1024 * 100); // 100 MB
uploader.setSizeMax(1024 * 1024 * 500); // 500 MB
// 上传文件
List<FileItem> items = uploader.parseRequest(req);
for (FileItem item : items) {
if (item.isFormField()) {
// 处理表单字段(非文件字段)
} else {
// 处理文件字段
String fileName = item.getName();
String contentType = item.getContentType();
long sizeInBytes = item.getSize();
InputStream dataInput = item.getInputStream();
// 处理文件
}
}
// 发送响应
resp.getWriter().print("Upload done.");
}
}
这个文件上传处理器中,注意以下几点:
- @WebServlet 注解的 url-pattern 属性值设为 "upload",与表单的 action 属性一致。
- @MultipartConfig 注解表示该 Servlet 是一个多部分文件上传的 Servlet。
- 检查是否为 multipart/form-data 表单。
- 配置上传参数,比如文件大小限制。
- 上传文件,使用 ServletFileUpload 类的 parseRequest() 方法解析 HttpServletRequest 中的数据,并返回一个 List<FileItem> 集合。
- 遍历 List<FileItem>,检查每个 FileItem 是表单字段还是文件字段。
- 如果是表单字段(非文件字段),可以通过 FileItem 的 getString() 或 getInputStream() 方法获取其值。
- 如果是文件字段,可以通过 FileItem 的 getName()、getContentType()、getSize() 和 getInputStream() 方法获取文件的元数据及内容。
下面是一个示例,将上传的文件都保存到服务器本地文件系统中。
@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 检查是否为 multipart/form-data 表单
if (!ServletFileUpload.isMultipartContent(req)) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Not a multipart request.");
return;
}
// 配置上传参数
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload uploader = new ServletFileUpload(factory);
uploader.setFileSizeMax(1024 * 1024 * 100); // 100 MB
uploader.setSizeMax(1024 * 1024 * 500); // 500 MB
// 上传文件
List<FileItem> items = uploader.parseRequest(req);
String fileDir = "/path/to/your/upload/dir/";
for (FileItem item : items) {
if (item.isFormField()) {
// 处理表单字段(非文件字段)
} else {
// 处理文件字段
String fileName = item.getName();
String contentType = item.getContentType();
long sizeInBytes = item.getSize();
InputStream dataInput = item.getInputStream();
// 保存文件
Path path = Paths.get(fileDir, fileName);
Files.copy(dataInput, path, StandardCopyOption.REPLACE_EXISTING);
// 处理文件
}
}
// 发送响应
resp.getWriter().print("Upload done.");
}
}
上面这个例子中,上传的文件都会保存到文件系统的 "/path/to/your/upload/dir/" 文件夹下,如果该文件夹不存在会自动创建。路径可以根据实际情况修改。
3. 文件上传进度监控
文件上传过程中,用户可能需要看到上传的进度,提示上传过程是否成功。可以使用 Ajax 轮询的方式实现文件上传进度监控。以下是一个示例:
<script>
function pollProgress() {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200 && xhr.responseText != "") {
var progress = JSON.parse(xhr.responseText);
document.getElementById("progress").innerHTML = progress.percent + "%";
if (progress.status == "IN_PROGRESS") {
setTimeout(pollProgress, 1000); // 每秒轮询一次
} else if (progress.status == "COMPLETED") {
alert("Upload done.");
} else if (progress.status == "FAILED") {
alert("Upload failed.");
}
}
};
xhr.open("GET", "upload-progress", true);
xhr.send();
}
</script>
<form onsubmit="pollProgress(); return false;">
请选择要上传的文件:<input type="file" name="file"><br/>
<input type="submit" value="上传">
</form>
<div id="progress"></div>
这个表单中,使用 onsubmit 事件调用 pollProgress() 函数,开始轮询上传进度。
@WebServlet("/upload-progress")
public class UploadProgressServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
UploadProgress progress = (UploadProgress) session.getAttribute("uploadProgress");
if (progress == null) {
resp.getWriter().print("");
return;
}
progress.updateStatus();
String jsonString = progress.toJsonString();
resp.setContentType("application/json");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().print(jsonString);
}
}
在之前的 UploadServlet 中,我们可以通过 HttpSession 把 UploadProgress 对象存储在 session 中,这样 UploadProgressServlet 可以在上传之外的任何时间获取到上传的进度,从而实现精确的轮询。
以下是 UploadProgress 的定义:
public class UploadProgress {
private final long totalSize;
private long uploadedSize;
private String status;
public UploadProgress(long totalSize) {
this.totalSize = totalSize;
this.uploadedSize = 0;
this.status = "IN_PROGRESS";
}
public synchronized void addUploadedSize(long size) {
uploadedSize += size;
}
public synchronized void updateStatus() {
if (uploadedSize >= totalSize) {
status = "COMPLETED";
} else if (status.equals("IN_PROGRESS")) {
status = "IN_PROGRESS";
} else {
status = "FAILED";
}
}
public float getPercent() {
return uploadedSize * 100.0F / totalSize;
}
public synchronized String toJsonString() {
return String.format("{\"percent\": %.2f, \"status\": \"%s\"}", getPercent(), status);
}
}
这个 UploadProgress 类,可以保存上传总大小、已上传大小、状态(IN_PROGRESS、COMPLETED、FAILED),以及提供一些操作方法,如更新已上传大小、更新状态、计算上传百分比和将 UploadProgress 对象转成 JSON 字符串等。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Jsp+Servlet实现文件上传下载 文件上传(一) - Python技术站