Il caricamento e il download di file tramite Servlet è un compito comune in un’applicazione web java. Dato che ho scritto molto recentemente riguardo le servlet java, ho pensato di fornire un esempio di caricamento di un file tramite servlet al server e quindi il download dal server al client.
Caricamento File tramite Servlet
Il nostro caso d’uso prevede di fornire una semplice pagina HTML in cui il client può selezionare un file locale da caricare sul server. Alla richiesta di caricamento del file, il nostro programma servlet caricherà il file in una directory del server e poi fornirà l’URL attraverso il quale l’utente può scaricare il file. Per motivi di sicurezza, all’utente non verrà fornito l’URL diretto per scaricare il file, invece gli verrà dato un link per scaricare il file e la nostra servlet elaborerà la richiesta e invierà il file all’utente. Creeremo un progetto web dinamico in Eclipse e la struttura del progetto apparirà come nell’immagine sottostante. Ora vediamo tutti i componenti della nostra applicazione web e capiamo l’implementazione.
Pagina HTML per caricare file Java sul server
È possibile caricare un file sul server inviando una richiesta post al servlet e inviando il modulo. Non è possibile utilizzare il metodo GET per caricare il file. Un altro punto da notare è che enctype del modulo dovrebbe essere multipart/form-data. Per selezionare un file dal sistema di file dell’utente, è necessario utilizzare l’elemento input con il type come file. Quindi possiamo avere una semplice pagina HTML index.html per caricare il file come segue:
<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>
Percorso del file sul server per il caricamento del file
Dobbiamo memorizzare il file in una directory sul server, possiamo avere questa directory codificata nel programma ma per una maggiore flessibilità, la manterremo configurabile nei parametri di contesto del descrittore di distribuzione. Inoltre aggiungeremo la nostra pagina html per il caricamento del file alla lista dei file di benvenuto. Il nostro file web.xml avrà un aspetto simile a quanto segue:
<?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 per la posizione di caricamento del file
Poiché abbiamo bisogno di leggere il parametro del contesto per la posizione del file e creare un oggetto File da esso, possiamo scrivere un ServletContextListener per farlo quando il contesto viene inizializzato. Possiamo impostare la posizione assoluta della directory e l’oggetto File come attributo del contesto da utilizzare da altri servlet. Il codice di implementazione del nostro ServletContextListener è come segue.
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) {
//esegui pulizia se necessario
}
}
Servlet di caricamento e scaricamento file
Aggiornamento: Le specifiche del Servlet 3 hanno aggiunto il supporto per caricare file sul server nell’API, quindi non avremo bisogno di utilizzare alcuna API di terze parti. Si prega di controllare Servlet 3 Upload File. Per il caricamento dei file, utilizzeremo l’utilità Apache Commons FileUpload; per il nostro progetto stiamo utilizzando la versione 1.3. FileUpload dipende dal jar Apache Commons IO, quindi dobbiamo inserire entrambi nella directory lib del progetto, come si può vedere nell’immagine sopra per la struttura del progetto. Utilizzeremo il factory DiskFileItemFactory che fornisce un metodo per analizzare l’oggetto HttpServletRequest e restituire un elenco di FileItem. FileItem fornisce metodi utili per ottenere il nome del file, il nome del campo nel modulo, le dimensioni e i dettagli del tipo di contenuto del file da caricare. Per scrivere il file in una directory, tutto ciò che dobbiamo fare è creare un oggetto File e passarlo come argomento al metodo write() di FileItem. Poiché lo scopo principale del servlet è caricare il file, sovrascriveremo il metodo init() per inizializzare l’istanza dell’oggetto DiskFileItemFactory
del servlet. Utilizzeremo questo oggetto nell’implementazione del metodo doPost() per caricare il file nella directory del server. Una volta che il file viene caricato con successo, invieremo una risposta al client con l’URL per scaricare il file. Poiché i collegamenti HTML utilizzano il metodo GET, aggiungeremo il parametro per il nome del file nell’URL e possiamo utilizzare lo stesso metodo doGet() del servlet per implementare il processo di download del file. Per implementare il servlet di download del file, prima apriremo l’InputStream per il file e utilizzeremo il metodo ServletContext.getMimeType() per ottenere il tipo MIME del file e impostarlo come tipo di contenuto della risposta. Dovremo anche impostare la lunghezza del contenuto della risposta come lunghezza del file. Per assicurarci che il client comprenda che stiamo inviando il file in risposta, dobbiamo impostare l’intestazione “Content-Disposition” con il valore “attachment; filename=“fileName”. Una volta completata la configurazione della risposta, possiamo leggere il contenuto del file da InputStream e scriverlo su ServletOutputStream e quindi svuotare l’output al client. La nostra implementazione finale del servlet UploadDownloadFileServlet assomiglia a quanto segue.
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>");
}
}
L’esecuzione di esempio del progetto è mostrata nelle immagini sottostanti.
Scarica il progetto di caricamento e download del file Servlet
Puoi scaricare il file jar di Apache Commons IO e il file jar di Apache Commons FileUpload dai seguenti URL. https://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi https://commons.apache.org/proper/commons-io/download_io.cgi
Scarica l’esempio di progetto di caricamento e download del file Servlet
Guarda il prossimo articolo della serie su Gestione delle eccezioni dei servlet.
Source:
https://www.digitalocean.com/community/tutorials/servlet-upload-file-download-example