در این بخش به نحوه آپلود کردن یک فایل بصورت multi part از سمت کاربر به سمت سرور و دریافت آن توسط Spring MVC میپردازیم
Spring MVC این امکان را میدهد که برای دریافت محتوای فایل بصورت multi part از پیاده سازی های MultipartResolver استفاده میکند که یکی بصورت ابجکت مشترک و دیگری با استفاده از servlet انجام میشود
همچنین خواهیم دید که Spring Boot چقدر مراحل کار را ساده تر میکند
CommonsMultipartResolver :
ابتدا کتابخانه آنرا به پروژه اضافه میکنیم :
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
برای استفاده از CommonsMultipartResolver باید یک Bean ایجاد کنیم :
@Bean(name = "multipartResolver") public CommonsMultipartResolver multipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setMaxUploadSize(100000); return multipartResolver; }
موقع تعریف این Bean باید موارد کنترلی مورد نیاز را ست کنیم مثلا در setMaxUploadSize حداکثر اندازه فایل آپلودی را میتوانیم تعیین کنیم
اگر بخواهیم از Servlet استفاده کنیم ورژن 3 از multipart حمایت میکند و دارای تنظیمات زیر است :
public class MainWebAppInitializer implements WebApplicationInitializer { private String TMP_FOLDER = "/tmp"; private int MAX_UPLOAD_SIZE = 5 * 1024 * 1024; @Override public void onStartup(ServletContext sc) throws ServletException { ServletRegistration.Dynamic appServlet = sc.addServlet("mvc", new DispatcherServlet( new GenericWebApplicationContext())); appServlet.setLoadOnStartup(1); MultipartConfigElement multipartConfigElement = new MultipartConfigElement(TMP_FOLDER, MAX_UPLOAD_SIZE, MAX_UPLOAD_SIZE * 2, MAX_UPLOAD_SIZE / 2); appServlet.setMultipartConfig(multipartConfigElement); } }
آرگومان های ابجکت MultipartConfigElement :
- مکان ذخیره فایل های دریافت شده
- حداکثر حجم فایل
- حداکثرحجم کل فایلها موقعی که در کلاینت چند فایل انتخاب شده باشد
- اندازه محتوایی که وقتی به آن رسید روی دیسک عملیات flush را انجام شود
* این تنظیمات در Servlet 3 باید همان ابتدای تنظیمات اعمال شود چون در servlet اجازه ست کردن آنها در MultipartResolver را نمیدهد
بعد از تنظیمات servlet میتوانیم از StandardServletMultipartResolver در قالب Bean استفاده کنیم :
@Bean public StandardServletMultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); }
یک فرم جهت آپلود فایل ایجاد میکنیم :
<form:form method="POST" action="/spring-mvc-xml/uploadFile" enctype="multipart/form-data"> <table> <tr> <td><form:label path="file">Select a file to upload</form:label></td> <td><input type="file" name="file" /></td> </tr> <tr> <td><input type="submit" value="Submit" /></td> </tr> </table> </form>
جهت دریافت در Controller@ میتوان در آرگومان ورودی متد مورد نظر یک ابجکت از نوع MultipartFile قرار دهیم این ابجکت جزییات فایل مانند نام فایل، نوع فایل و... را میتواند به ما بدهد
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST) public String submit(@RequestParam("file") MultipartFile file, ModelMap modelMap) { modelMap.addAttribute("file", file); return "fileUploadView"; }
میتوانیم از اطلاعات دریافتی MultipartFile در صفحه View نیز استفاده کنیم :
<h2>Submitted File</h2> <table> <tr> <td>OriginalFileName:</td> <td>${file.originalFilename}</td> </tr> <tr> <td>Type:</td> <td>${file.contentType}</td> </tr> </table>
ارسال چندین فایل در یک درخواست :
<form:form method="POST" action="/spring-mvc-java/uploadMultiFile" enctype="multipart/form-data"> <table> <tr> <td>Select a file to upload</td> <td><input type="file" name="files" /></td> </tr> <tr> <td>Select a file to upload</td> <td><input type="file" name="files" /></td> </tr> <tr> <td>Select a file to upload</td> <td><input type="file" name="files" /></td> </tr> <tr> <td><input type="submit" value="Submit" /></td> </tr> </table> </form:form>
در کنترلر میتوانیم انرا در قالب آرایه ای از MultipartFile دریافت کنیم :
@RequestMapping(value = "/uploadMultiFile", method = RequestMethod.POST) public String submit(@RequestParam("files") MultipartFile[] files, ModelMap modelMap) { modelMap.addAttribute("files", files); return "fileUploadView"; }
و اطلاعات دریافتی را در View ست کنیم و به کاربر برگردانیم :
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Spring MVC File Upload</title> </head> <body> <h2>Submitted Files</h2> <table> <c:forEach items="${files}" var="file"> <tr> <td>OriginalFileName:</td> <td>${file.originalFilename}</td> </tr> <tr> <td>Type:</td> <td>${file.contentType}</td> </tr> </c:forEach> </table> </body> </html>
در یک فرمی که فیلدی برای آپلود فایل وجود داشته باشید بسیار محتمل است که فیلد های دیگری هم برای ارسال وجود داشته باشد :
<form:form method="POST" action="/spring-mvc-java/uploadFileWithAddtionalData" enctype="multipart/form-data"> <table> <tr> <td>Name</td> <td><input type="text" name="name" /></td> </tr> <tr> <td>Email</td> <td><input type="text" name="email" /></td> </tr> <tr> <td>Select a file to upload</td> <td><input type="file" name="file" /></td> </tr> <tr> <td><input type="submit" value="Submit" /></td> </tr> </table> </form:form>
حال این اطلاعات اضافی را چطور باید در Controller دریافت کنیم :
@PostMapping("/uploadFileWithAddtionalData") public String submit( @RequestParam MultipartFile file, @RequestParam String name, @RequestParam String email, ModelMap modelMap) { modelMap.addAttribute("name", name); modelMap.addAttribute("email", email); modelMap.addAttribute("file", file); return "fileUploadView"; }
این اطلاعات دریافتی را میتوانیم بجای ست کردن متغییر های مختلف برای فیلد های فرم از یک ابجکت Model استفاده کنیم و با استفاده از ModelAttribute@ آنرا پر کنیم :
public class FormDataWithFile { private String name; private String email; private MultipartFile file; // standard getters and setters }
@PostMapping("/uploadFileModelAttribute") public String submit(@ModelAttribute FormDataWithFile formDataWithFile, ModelMap modelMap) { modelMap.addAttribute("formDataWithFile", formDataWithFile); return "fileUploadView"; }
آپلود کردن فایل بوسیله Spring Boot :
بوسیله Spring Boot خواهیم دید که چقدر کار راحتتر خواهد شد
ابتدا مطمئن شوید که کتابخانه آنرا به پروژه اضافه کرده اید :
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.1.8.RELEASE</version> </dependency>
برای ست کردن تنظیمات کافی است در application.properties آنها را تنظیم کنیم :
spring.servlet.multipart.max-file-size=128KB spring.servlet.multipart.max-request-size=128KB
و
spring.servlet.multipart.enabled=true spring.servlet.multipart.location=${java.io.tmpdir}
اگر به ${java.io.tmpdir} توجه کنید ما یک مکان موقتی را برای ذخیره محتوای فایل انتخاب کردیم این بدین معنی است که بعد از آپلود شدن فایل موقتا نگهداری خواهد شد