היום נבחן דוגמת העלאת קובץ של Servlet 3 באמצעות הערה @MultipartConfig ו-javax.servlet.http.Part
. לפני זמן קצר כתבתי מאמר על העלאת קובץ של Servlet והשתמשתי ב- Apache FileUpload API, אך כאן נשתמש בתכונה להעלאת קבצים של Servlet 3.
העלאת קובץ של Servlet 3
מאחר והעלאת קבצים היא משימה נפוצה ביישומי האינטרנט, המפרט של Servlet 3.0 סיפק תמיכה נוספת בהעלאת קבצים לשרת ואין צורך להיעזר ב- API של צד שלישי עבור זה. במדריך זה נראה כיצד ניתן להשתמש ב- API של Servlet 3.0 להעלאת קבצים לשרת.
MultipartConfig
עלינו לסמן את סרבל טפס העלאת הקבצים עם ההערה MultipartConfig כדי לטפל בבקשות multipart/form-data שמשמשות להעלאת קובץ לשרת. ההערה MultipartConfig מכילה את המאפיינים הבאים:
- fileSizeThreshold: ניתן לציין את אחוזת הגודל אחריו הקובץ ייכתב לדיסק. ערך הגודל בבתים, כך ש-1024*1024*10 הוא 10 מגה-בתים.
- מיקום: ספריית המיקום בה יאוחסנו הקבצים כברירת מחדל, הערך המחדל שלו הוא "".
- maxFileSize: הגודל המרבי המותר להעלאת קובץ, הערך מסופק בבתים. הערך המחדל שלו הוא -1L, שפירושו לא מוגבל.
- maxRequestSize: הגודל המרבי המותר לבקשת multipart/form-data. הערך המחדל שלו הוא -1L, שפירושו לא מוגבל.
קרא עוד אודות הערות ב-מדריך להערות ב-Java.
ממשק Part
ממשק Part מייצג חלק או פריט טופס שהתקבל בתוך בקשת POST של multipart/form-data. כמה מתודות חשובות הן getInputStream()
, write(String fileName)
שאנו יכולים להשתמש בהן כדי לקרוא ולכתוב קבצים.
שינויים ב-HttpServletRequest
נוספו שיטות חדשות ב־HttpServletRequest
כדי לקבל את כל החלקים בבקשת multipart/form-data דרך השיטה getParts()
. נוכל לקבל חלק מסוים באמצעות השיטה getPart(String partName)
. בואו נראה פרויקט פשוט שבו נשתמש בשיטות ה־API הנ"ל כדי להעלות קובץ באמצעות servlet. מבנה הפרויקט שלנו יראה כמו בתמונה למטה.
טופס HTML
יש לנו דף HTML פשוט בו ניתן לבחור את הקובץ להעלאה ולשלוח את הבקשה לשרת כדי להעלות אותו. 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>
Servlet להעלאת קבצים
זהו סקריפט העלאת הקבצים שלנו. FileUploadServlet.java
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 {
// מקבל את הנתיב המוחלט של היישום באינטרנט
String applicationPath = request.getServletContext().getRealPath("");
// בונה את הנתיב לתיקייה לשמירת הקובץ שהועלה
String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;
// יוצר את תיקיית השמירה אם היא לא קיימת
File fileSaveDir = new File(uploadFilePath);
if (!fileSaveDir.exists()) {
fileSaveDir.mkdirs();
}
System.out.println("Upload File Directory="+fileSaveDir.getAbsolutePath());
String fileName = null;
// מקבל את כל החלקים מהבקשה ומכתיב אותם לקובץ בשרת
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 "";
}
}
שים לב לשימוש בהערה @MultipartConfig כדי לציין פרמטרים שונים של גודל להעלאת קובץ. אנו צריכים להשתמש במאפיין "content-disposition" של כותרת הבקשה כדי לקבל את שם הקובץ שנשלח על ידי הלקוח, נשמור את הקובץ באותו שם. מיקום התיקייה נמצא יחסית ליישום האינטרנטי בו אני שומר את הקובץ, ניתן להגדיר אותו למיקום אחר כמו בדוגמת Apache Commons FileUpload.
תגובה JSP
A simple JSP page that will be sent as response to client once the file is uploaded successfully to server. 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>
תיאור ההפצה
אין שינויים חדשים בקובץ web.xml להעלאת קובץ servlet, הוא משמש רק להגדיר את index.html כקובץ ברוך. 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>
כעת כאשר אנו מריצים את היישום, אנו מקבלים דפים הבאים כתגובה.
הלוגים יציגו את מיקום התיקייה בו הקובץ נשמר ואת מידע כותרת התוכן של 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"
I am running Tomcat through Eclipse, that’s why file location is like this. If you run tomcat through command line and deploy application by exporting as WAR file into webapps directory, you will get different structure but a clear one.
Source:
https://www.digitalocean.com/community/tutorials/servlet-3-file-upload-multipartconfig-part