Il caricamento di file è un compito molto comune in qualsiasi applicazione web. Abbiamo già visto come caricare file in Servlet e Caricamento file in Struts2. Oggi impareremo su Spring File upload, in particolare su Spring MVC File Upload per file singoli e multipli.
Spring MVC File Upload
Il framework Spring MVC fornisce supporto per il caricamento dei file integrando l’API Apache Commons FileUpload. Il processo per caricare i file è molto semplice e richiede configurazioni semplici. Creeremo un semplice progetto Spring MVC in STS che assomiglierà all’immagine sottostante. La maggior parte del codice è generato dallo strumento STS, ci concentreremo sulle modifiche necessarie per utilizzare l’integrazione del caricamento file di Spring.
Dependencies Maven per Apache Commons FileUpload
Prima di tutto, dobbiamo aggiungere le dipendenze di Apache Commons FileUpload nel nostro file pom.xml, in modo che i file jar richiesti facciano parte dell’applicazione web. Di seguito è riportato il frammento di dipendenza dal mio file pom.xml.
<!-- Apache Commons FileUpload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Apache Commons IO -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
Visualizzazioni del modulo di caricamento file di Spring
Crea due pagine JSP per consentire il caricamento di file singoli e multipli nell’applicazione web di Spring. Codice della vista upload.jsp:
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Upload File Request Page</title>
</head>
<body>
<form method="POST" action="uploadFile" enctype="multipart/form-data">
File to upload: <input type="file" name="file"><br />
Name: <input type="text" name="name"><br /> <br />
<input type="submit" value="Upload"> Press here to upload the file!
</form>
</body>
</html>
Codice della vista uploadMultiple.jsp:
<%@ taglib uri="https://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Upload Multiple File Request Page</title>
</head>
<body>
<form method="POST" action="uploadMultipleFile" enctype="multipart/form-data">
File1 to upload: <input type="file" name="file"><br />
Name1: <input type="text" name="name"><br /> <br />
File2 to upload: <input type="file" name="file"><br />
Name2: <input type="text" name="name"><br /> <br />
<input type="submit" value="Upload"> Press here to upload the file!
</form>
</body>
</html>
Nota che questi file sono semplici file HTML, non sto usando tag JSP o Spring per evitare complessità. Il punto importante da notare è che l’attributo enctype del form deve essere impostato su multipart/form-data, in modo che l’applicazione web di Spring sappia che la richiesta contiene dati del file da elaborare. Nota anche che per i file multipli, il campo del form “file” e “name” sono gli stessi nei campi di input, in modo che i dati vengano inviati sotto forma di un array. Prenderemo l’array di input, analizzeremo i dati del file e li memorizzeremo nel nome file specificato.
Configurazione multipart di Spring MVC
Per utilizzare Apache Commons FileUpload per gestire le richieste multipart, tutto ciò di cui abbiamo bisogno è configurare il bean multipartResolver
con la classe come org.springframework.web.multipart.commons.CommonsMultipartResolver
. Il nostro file di configurazione finale di Spring appare come segue. Codice servlet-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/**" location="/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<beans:bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- setting maximum upload size -->
<beans:property name="maxUploadSize" value="100000" />
</beans:bean>
<context:component-scan base-package="com.journaldev.spring.controller" />
</beans:beans>
Nota che sto impostando il limite di dimensione massima per il caricamento fornendo il valore della proprietà maxUploadSize per il bean multipartResolver. Se osservi il codice sorgente della classe DispatcherServlet
, vedrai che viene definita e inizializzata una variabile MultipartResolver con il nome multipartResolver nel metodo sottostante.
private void initMultipartResolver(ApplicationContext context)
{
try
{
this.multipartResolver = ((MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class));
if (this.logger.isDebugEnabled()) {
this.logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex)
{
this.multipartResolver = null;
if (this.logger.isDebugEnabled())
this.logger.debug("Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided");
}
}
Con questa configurazione, qualsiasi richiesta con enctype come multipart/form-data verrà gestita da multipartResolver prima di essere passata alla classe Controller.
Classe Controller per il caricamento di file Spring
La classe Controller è molto semplice, dobbiamo definire metodi handler per gli URI uploadFile e uploadMultipleFile. Codice FileUploadController.java:
package com.journaldev.spring.controller;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
/**
* Handles requests for the application file upload requests
*/
@Controller
public class FileUploadController {
private static final Logger logger = LoggerFactory
.getLogger(FileUploadController.class);
/**
* Upload single file using Spring Controller
*/
@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
public @ResponseBody
String uploadFileHandler(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
// Creazione della directory per memorizzare il file
String rootPath = System.getProperty("catalina.home");
File dir = new File(rootPath + File.separator + "tmpFiles");
if (!dir.exists())
dir.mkdirs();
// Creare il file sul server
File serverFile = new File(dir.getAbsolutePath()
+ File.separator + name);
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(serverFile));
stream.write(bytes);
stream.close();
logger.info("Server File Location="
+ serverFile.getAbsolutePath());
return "You successfully uploaded file=" + name;
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
} else {
return "You failed to upload " + name
+ " because the file was empty.";
}
}
/**
* Upload multiple file using Spring Controller
*/
@RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST)
public @ResponseBody
String uploadMultipleFileHandler(@RequestParam("name") String[] names,
@RequestParam("file") MultipartFile[] files) {
if (files.length != names.length)
return "Mandatory information missing";
String message = "";
for (int i = 0; i < files.length; i++) {
MultipartFile file = files[i];
String name = names[i];
try {
byte[] bytes = file.getBytes();
// Creazione della directory per memorizzare il file
String rootPath = System.getProperty("catalina.home");
File dir = new File(rootPath + File.separator + "tmpFiles");
if (!dir.exists())
dir.mkdirs();
// Creare il file sul server
File serverFile = new File(dir.getAbsolutePath()
+ File.separator + name);
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(serverFile));
stream.write(bytes);
stream.close();
logger.info("Server File Location="
+ serverFile.getAbsolutePath());
message = message + "You successfully uploaded file=" + name
+ "
";
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
}
return message;
}
}
Nota l’uso delle annotazioni di Spring che rendono la nostra vita più facile e il codice sembra più leggibile. Il metodo uploadFileHandler
è utilizzato per gestire il caricamento di singoli file, mentre il metodo uploadMultipleFileHandler
è utilizzato per gestire il caricamento di più file. In realtà potremmo avere un unico metodo per gestire entrambi gli scenari. Ora esportare l’applicazione come file WAR e distribuirla nel contenitore servlet Tomcat. Quando eseguiamo la nostra applicazione, di seguito le immagini mostrano le richieste e le risposte.
Esempio di caricamento file di Spring MVC
Puoi controllare i log del server per sapere la posizione in cui i file sono stati memorizzati. Scarica il progetto dal link sopra e gioca con esso per saperne di più.