Caricamento File Servlet 3 – @MultipartConfig, Part

Oggi esamineremo l’esempio di caricamento file Servlet 3 utilizzando l’annotazione @MultipartConfig e javax.servlet.http.Part. Tempo fa ho scritto un articolo su Servlet File Upload e ho utilizzato l’API Apache FileUpload, ma qui utilizzeremo la funzionalità di caricamento file Servlet 3.

Caricamento file Servlet 3

Poiché il caricamento di file è un’operazione comune nelle applicazioni web, le specifiche Servlet 3.0 forniscono un supporto aggiuntivo per il caricamento dei file sul server e non dobbiamo dipendere da alcuna API di terze parti per questo. In questo tutorial vedremo come utilizzare l’API Servlet 3.0 per caricare i file sul server.

MultipartConfig

Dobbiamo annotare il gestore di caricamento file servlet con l’annotazione MultipartConfig per gestire le richieste multipart/form-data che vengono utilizzate per caricare il file sul server. L’annotazione MultipartConfig ha i seguenti attributi:

  • fileSizeThreshold: Possiamo specificare la soglia di dimensione dopo la quale il file verrà scritto su disco. Il valore della dimensione è in byte, quindi 1024*1024*10 corrisponde a 10 MB.
  • posizione: Directory in cui i file verranno memorizzati per impostazione predefinita, il suo valore predefinito è “”.
  • maxFileSize: Dimensione massima consentita per caricare un file, il valore è fornito in byte. Il valore predefinito è -1L, il che significa illimitato.
  • maxRequestSize: Dimensione massima consentita per la richiesta multipart/form-data. Il valore predefinito è -1L, il che significa illimitato.

Leggi di più sulle annotazioni su Java Annotations Tutorial.

Interfaccia Part

L’interfaccia Part rappresenta una parte o un elemento del modulo ricevuto all’interno di una richiesta POST multipart/form-data. Alcuni metodi importanti sono getInputStream(), write(String fileName) che possiamo utilizzare per leggere e scrivere file.

Modifiche HttpServletRequest

I nuovi metodi sono stati aggiunti in HttpServletRequest per ottenere tutte le parti nella richiesta multipart/form-data attraverso il metodo getParts(). Possiamo ottenere una parte specifica usando il metodo getPart(String partName). Vediamo un progetto semplice dove useremo i metodi API sopra per caricare un file usando il servlet. La struttura del nostro progetto sarà simile all’immagine sottostante.

Modulo HTML

Abbiamo una semplice pagina html dove possiamo selezionare il file da caricare e inviare la richiesta al server per caricarlo. 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 di Caricamento File

Ecco l’implementazione del nostro servlet di caricamento file. 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 {
        // ottiene il percorso assoluto dell'applicazione web
        String applicationPath = request.getServletContext().getRealPath("");
        // costruisce il percorso della directory per salvare il file caricato
        String uploadFilePath = applicationPath + File.separator + UPLOAD_DIR;
         
        // crea la directory di salvataggio se non esiste
        File fileSaveDir = new File(uploadFilePath);
        if (!fileSaveDir.exists()) {
            fileSaveDir.mkdirs();
        }
        System.out.println("Upload File Directory="+fileSaveDir.getAbsolutePath());
        
        String fileName = null;
        // Ottiene tutte le parti dalla richiesta e le scrive nel file sul server
        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 "";
    }
}

Notare l’uso dell’annotazione @MultipartConfig per specificare diversi parametri di dimensione per il file da caricare. Dobbiamo utilizzare l’attributo “content-disposition” dell’intestazione della richiesta per ottenere il nome del file inviato dal client; salveremo il file con lo stesso nome. La posizione della directory è relativa all’applicazione web dove sto salvando il file, è possibile configurarla in un’altra posizione come nell’esempio di Apache Commons FileUpload.

Risposta 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>

Descrittore di distribuzione

Non c’è niente di nuovo nel file web.xml per il caricamento del file servlet, viene solo utilizzato per rendere index.html il file di benvenuto. 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>

Ora, quando eseguiamo l’applicazione, otteniamo le seguenti pagine come risposta. I log mostreranno la posizione della directory in cui è salvato il file e le informazioni sull’intestazione “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.

Scarica il progetto di caricamento file multipart in Servlet 3

Source:
https://www.digitalocean.com/community/tutorials/servlet-3-file-upload-multipartconfig-part