تحميل وتنزيل الملف في سيرفلت هي مهمة شائعة في تطبيق ويب جافا. نظرًا لأنني كتبت الكثير حول سيرفلت جافا مؤخرًا، فكرت في تقديم مثال على تحميل الملف إلى الخادم باستخدام السيرفلت ومن ثم التنزيل من الخادم إلى العميل.
تحميل ملف السيرفلت
حالتنا هي توفير صفحة HTML بسيطة حيث يمكن للعميل اختيار ملف محلي لتحميله إلى الخادم. عند تقديم طلب لتحميل الملف، سيقوم برنامج السيرفلت لدينا بتحميل الملف إلى دليل في الخادم ثم يقدم عنوان URL من خلاله يمكن للمستخدم تنزيل الملف. لأسباب أمان، لن يتم توفير عنوان URL المباشر للمستخدم لتنزيل الملف، بل سيتم منحهم رابطًا لتنزيل الملف وسيقوم برنامج السيرفلت لدينا بمعالجة الطلب وإرسال الملف إلى المستخدم. سنقوم بإنشاء مشروع ويب ديناميكي في إكليبس، وستبدو هيكلة المشروع كما في الصورة أدناه. دعونا نلقي نظرة على جميع مكونات تطبيق الويب الديناميكي الخاص بنا ونفهم التنفيذ.
صفحة HTML لتحميل ملف Java إلى الخادم
يمكننا تحميل ملف إلى الخادم عن طريق إرسال طلب POST إلى سيرفليت وتقديم النموذج. لا يمكننا استخدام طريقة GET لتحميل الملف. نقطة أخرى للملاحظة هي أن enctype للنموذج يجب أن يكون multipart/form-data. لتحديد ملف من نظام ملفات المستخدم، نحتاج إلى استخدام عنصر input بنوع file. لذا يمكننا أن نمتلك صفحة HTML بسيطة index.html لتحميل الملف كما يلي:
<html>
<head></head>
<body>
<form action="UploadDownloadFileServlet" method="post" enctype="multipart/form-data">
Select File to Upload:<input type="file" name="fileName">
<br>
<input type="submit" value="Upload">
</form>
</body>
</html>
موقع ملف الخادم لتحميل الملف
يجب علينا تخزين الملف في دليل ما على الخادم، يمكننا تضمين هذا الدليل بشكل صلب في البرنامج ولكن لضمان المرونة الأفضل، سنجعله قابلاً للتكوين في معلمات سياق الوصف. كما سنضيف صفحة 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>ServletFileUploadDownloadExample</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>tempfile.dir</param-name>
<param-value>tmpfiles</param-value>
</context-param>
</web-app>
ServletContextListener لموقع تحميل ملف الخادم
منذ أن نحتاج إلى قراءة معلمة السياق لموقع الملف وإنشاء كائن File منه، يمكننا كتابة ServletContextListener للقيام بذلك عندما يتم تهيئة السياق. يمكننا تعيين موقع الدليل المطلق وكائن File كسمة سياق لاستخدامها من قبل السيرفلتات الأخرى. كود تنفيذ ServletContextListener لدينا يشبه ما يلي.
package com.journaldev.servlet;
import java.io.File;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class FileLocationContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
String rootPath = System.getProperty("catalina.home");
ServletContext ctx = servletContextEvent.getServletContext();
String relativePath = ctx.getInitParameter("tempfile.dir");
File file = new File(rootPath + File.separator + relativePath);
if(!file.exists()) file.mkdirs();
System.out.println("File Directory created to be used for storing files");
ctx.setAttribute("FILES_DIR_FILE", file);
ctx.setAttribute("FILES_DIR", rootPath + File.separator + relativePath);
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
// إجراء التنظيف إذا كان الأمر ضروري
}
}
سيرفلت تحميل تنزيل الملف
تحديث: تمت إضافة دعم لتحميل الملفات على الخادم في مواصفات سيرفلت 3 في واجهة برمجة التطبيقات، لذلك لن نحتاج إلى استخدام أي واجهة برمجة تطبيقات من طرف ثالث. يرجى التحقق من تحميل ملف سيرفلت 3. بالنسبة لتحميل الملفات، سنستخدم أداة Apache Commons FileUpload، والتي نستخدم الإصدار 1.3 منها في مشروعنا. FileUpload يعتمد على مكتبة Apache Commons IO، لذا نحتاج إلى وضع كلتاهما في دليل lib للمشروع، كما يمكنك رؤية ذلك في الصورة أعلاه لهيكل المشروع. سنستخدم مصنع DiskFileItemFactory الذي يوفر طريقة لتحليل كائن HttpServletRequest وإرجاع قائمة FileItem. توفر FileItem طرقًا مفيدة للحصول على اسم الملف، واسم الحقل في النموذج، وحجم وتفاصيل نوع المحتوى للملف الذي يجب تحميله. لكتابة الملف إلى دليل، كل ما علينا القيام به هو إنشاء كائن File وتمريره كمعامل إلى طريقة write() في FileItem. نظرًا لأن الغرض الرئيسي من سيرفلت هو تحميل الملف، سنقوم بتجاوز طريقة init() لتهيئة كائن DiskFileItemFactory للسيرفلت. سنستخدم هذا الكائن في تنفيذ طريقة doPost() لتحميل الملف إلى دليل الخادم. بمجرد أن يتم تحميل الملف بنجاح، سنرسل استجابة إلى العميل بعنوان URL لتنزيل الملف، نظرًا لأن روابط HTML تستخدم الطريقة GET، سنقوم بإلحاق المعلمة لاسم الملف في عنوان URL ويمكننا استخدام نفس طريقة doGet() في السيرفلت لتنفيذ عملية تنزيل الملف. لتنفيذ سيرفلت تنزيل الملف، سنفتح أولاً InputStream للملف ونستخدم طريقة ServletContext.getMimeType() للحصول على نوع MIME للملف وتعيينه كنوع محتوى للرد. سيتعين علينا أيضًا تعيين طول محتوى الرد كطول للملف. للتأكد من أن العميل يفهم أننا نرسل ملفًا في الرد، نحتاج إلى تعيين رأس “Content-Disposition” بقيمة “attachment; filename=“fileName”. بمجرد الانتهاء من تعيين تكوين الرد، يمكننا قراءة محتوى الملف من InputStream وكتابته إلى ServletOutputStream ومن ثم تفريغ الإخراج إلى العميل. تبدو التنفيذ النهائي لسيرفلت UploadDownloadFileServlet كما يلي.
package com.journaldev.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@WebServlet("/UploadDownloadFileServlet")
public class UploadDownloadFileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private ServletFileUpload uploader = null;
@Override
public void init() throws ServletException{
DiskFileItemFactory fileFactory = new DiskFileItemFactory();
File filesDir = (File) getServletContext().getAttribute("FILES_DIR_FILE");
fileFactory.setRepository(filesDir);
this.uploader = new ServletFileUpload(fileFactory);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String fileName = request.getParameter("fileName");
if(fileName == null || fileName.equals("")){
throw new ServletException("File Name can't be null or empty");
}
File file = new File(request.getServletContext().getAttribute("FILES_DIR")+File.separator+fileName);
if(!file.exists()){
throw new ServletException("File doesn't exists on server.");
}
System.out.println("File location on server::"+file.getAbsolutePath());
ServletContext ctx = getServletContext();
InputStream fis = new FileInputStream(file);
String mimeType = ctx.getMimeType(file.getAbsolutePath());
response.setContentType(mimeType != null? mimeType:"application/octet-stream");
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
ServletOutputStream os = response.getOutputStream();
byte[] bufferData = new byte[1024];
int read=0;
while((read = fis.read(bufferData))!= -1){
os.write(bufferData, 0, read);
}
os.flush();
os.close();
fis.close();
System.out.println("File downloaded at client successfully");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(!ServletFileUpload.isMultipartContent(request)){
throw new ServletException("Content type is not multipart/form-data");
}
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.write("<html><head></head><body>");
try {
List<FileItem> fileItemsList = uploader.parseRequest(request);
Iterator<FileItem> fileItemsIterator = fileItemsList.iterator();
while(fileItemsIterator.hasNext()){
FileItem fileItem = fileItemsIterator.next();
System.out.println("FieldName="+fileItem.getFieldName());
System.out.println("FileName="+fileItem.getName());
System.out.println("ContentType="+fileItem.getContentType());
System.out.println("Size in bytes="+fileItem.getSize());
File file = new File(request.getServletContext().getAttribute("FILES_DIR")+File.separator+fileItem.getName());
System.out.println("Absolute Path at server="+file.getAbsolutePath());
fileItem.write(file);
out.write("File "+fileItem.getName()+ " uploaded successfully.");
out.write("<br>");
out.write("<a href=\"UploadDownloadFileServlet?fileName="+fileItem.getName()+"\">Download "+fileItem.getName()+"</a>");
}
} catch (FileUploadException e) {
out.write("Exception in uploading file.");
} catch (Exception e) {
out.write("Exception in uploading file.");
}
out.write("</body></html>");
}
}
تظهر تنفيذ عينة المشروع في الصور أدناه.
تنزيل ملف سيرفليت تحميل مشروع التنزيل
يمكنك تنزيل ملف جار Apache Commons IO وملف جار Apache Commons FileUpload من الروابط أدناه. https://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi https://commons.apache.org/proper/commons-io/download_io.cgi
تنزيل ملف سيرفليت تحميل مشروع مثال التنزيل
تحقق من المقالة التالية في السلسلة حول التعامل مع استثناءات الـ Servlet Servlet Exception Handling.
Source:
https://www.digitalocean.com/community/tutorials/servlet-upload-file-download-example