Hôm nay chúng ta sẽ xem xét ví dụ upload file trong Servlet 3 sử dụng annotation @MultipartConfig
và javax.servlet.http.Part
. Trước đây tôi đã viết một bài báo về upload file trong Servlet và tôi đã sử dụng API Apache FileUpload nhưng ở đây chúng ta sẽ sử dụng tính năng upload file của Servlet 3.
Upload file trong Servlet 3
Vì upload file là một tác vụ phổ biến trong các ứng dụng web, Servlet Specs 3.0 đã cung cấp hỗ trợ bổ sung cho việc tải tệp lên máy chủ và chúng ta không phải phụ thuộc vào bất kỳ API bên thứ ba nào cho việc này. Trong hướng dẫn này, chúng ta sẽ xem cách sử dụng API Servlet 3.0 để tải tệp lên máy chủ.
MultipartConfig
Chúng ta cần annotate servlet xử lý tải tệp với @MultipartConfig
để xử lý các yêu cầu multipart/form-data
được sử dụng để tải tệp lên máy chủ. Annotation MultipartConfig
có các thuộc tính sau:
fileSizeThreshold
: Chúng ta có thể chỉ định ngưỡng kích thước mà sau đó tệp sẽ được ghi vào đĩa. Giá trị kích thước tính bằng byte, vì vậy1024*1024*10
là 10 MB.location
: Thư mục nơi các tệp sẽ được lưu trữ theo mặc định, giá trị mặc định của nó là “”.maxFileSize
: Kích thước tối đa được phép tải lên một tệp, giá trị của nó được cung cấp bằng byte. Giá trị mặc định của nó là1L
có nghĩa là không giới hạn.maxRequestSize
: Kích thước tối đa được phép cho yêu cầumultipart/form-data
. Giá trị mặc định là1L
có nghĩa là không giới hạn.
Giao diện Part
Giao diện Part
đại diện cho một phần hoặc mục biểu mẫu được nhận trong yêu cầu POST multipart/form-data
. Một số phương thức quan trọng là getInputStream()
, write(String fileName)
mà chúng ta có thể sử dụng để đọc và ghi tệp.
Thay đổi trong HttpServletRequest
Các phương thức mới đã được thêm vào HttpServletRequest
để lấy tất cả các phần trong yêu cầu multipart/form-data
thông qua phương thức getParts()
. Chúng ta có thể lấy một phần cụ thể bằng cách sử dụng phương thức getPart(String partName)
. Hãy xem một dự án đơn giản nơi chúng ta sẽ sử dụng các phương thức API trên để tải tệp lên bằng servlet
. Cấu trúc dự án của chúng ta sẽ trông như hình dưới đây.
Biểu mẫu HTML
Chúng ta có một trang HTML đơn giản nơi chúng ta có thể chọn tệp để tải lên và gửi yêu cầu đến máy chủ để tải nó lên. index.html
<html>
<head></head>
<body>
<form action="FileUploadServlet" method="post" enctype="multipart/form-data">
Select File to Upload:<input type="file" name="fileName">
<br>
<input type="submit" value="Upload">
</form>
</body>
</html>
Tải tệp lên Servlet
Đây là cách triển khai FileUploadServlet.java
của chúng ta:
package com.journaldev.servlet;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet("/FileUploadServlet")
@MultipartConfig(fileSizeThreshold=1024*1024*10, // 10 MB
maxFileSize=1024*1024*50, // 50 MB
maxRequestSize=1024*1024*100) // 100 MB
public class FileUploadServlet extends HttpServlet {
private static final long serialVersionUID = 205242440643911308L;
/**
* Directory where uploaded files will be saved, its relative to
* the web application directory.
*/
private static final String UPLOAD_DIR = "uploads";
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// gets absolute path of the web application
String applicationPath = request.getServletContext().getRealPath("");
// constructs path of the directory to save uploaded file
String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;
// creates the save directory if it does not exists
File fileSaveDir = new File(uploadFilePath);
if (!fileSaveDir.exists()) {
fileSaveDir.mkdirs();
}
System.out.println("Upload File Directory="+fileSaveDir.getAbsolutePath());
String fileName = null;
//Get all the parts from request and write it to the file on server
for (Part part : request.getParts()) {
fileName = getFileName(part);
part.write(uploadFilePath + File.separator + fileName);
}
request.setAttribute("message", fileName + " File uploaded successfully!");
getServletContext().getRequestDispatcher("/response.jsp").forward(
request, response);
}
/**
* Utility method to get file name from HTTP header content-disposition
*/
private String getFileName(Part part) {
String contentDisp = part.getHeader("content-disposition");
System.out.println("content-disposition header= "+contentDisp);
String[] tokens = contentDisp.split(";");
for (String token : tokens) {
if (token.trim().startsWith("filename")) {
return token.substring(token.indexOf("=") + 2, token.length()-1);
}
}
return "";
}
}
Bạn hãy chú ý rằng chúng ta sử dụng @MultipartConfig
để chỉ định các tham số kích thước khác nhau cho tệp tải lên. Để lấy tên tệp do máy khách gửi, chúng ta cần dùng thuộc tính “content-disposition” của tiêu đề yêu cầu; tệp sẽ được lưu với tên đó. Thư mục lưu tệp hiện đang tương đối so với ứng dụng web, nhưng bạn hoàn toàn có thể cấu hình nó sang một vị trí khác, chẳng hạn như trong ví dụ Apache Commons FileUpload.
Trang JSP phản hồi
Đây là một trang JSP đơn giản sẽ được gửi lại cho máy khách làm phản hồi ngay khi tệp được tải lên máy chủ thành công: response.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"<https://www.w3.org/TR/html4/loose.dtd>">
<html>
<head>
<title>Upload File Response</title>
</head>
<body>
<%-- Using JSP EL to get message attribute value from request scope --%>
<h2>${requestScope.message}</h2>
</body>
</html>
Deployment Descriptor
Không có gì mới trong tệp web.xml
cho việc upload file bằng servlet
cả, nó chỉ được dùng để đặt index.html
làm tệp chào mừng thôi.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>" xmlns="<https://java.sun.com/xml/ns/javaee>" xsi:schemaLocation="<https://java.sun.com/xml/ns/javaee> <https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd>" version="3.0">
<display-name>ServletFileUploadExample</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
Khi chúng ta chạy ứng dụng, chúng ta sẽ nhận được các trang sau làm phản hồi.
Các nhật ký logs (nhật ký) sẽ hiển thị vị trí thư mục nơi tệp được lưu và thông tin tiêu đề content-disposition.
Upload File Directory=/Users/pankaj/Documents/workspace/j2ee/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/ServletFileUploadExample/uploads
content-disposition header= form-data; name="fileName"; filename="IMG_2046.jpg"
Tôi đang chạy Tomcat qua Eclipse, đó là lý do tại sao vị trí tệp lại như vậy. Nếu bạn chạy Tomcat bằng dòng lệnh và triển khai ứng dụng bằng cách xuất thành tệp WAR vào thư mục webapps
, bạn sẽ thấy cấu trúc khác nhưng rõ ràng hơn.