MokaByte Numero  37  - Gennaio 2000 
FileUpload con 
i Servlet
di 
Ferdi Carcavallo
Come gestire l’upload di files via web  in 
tramite servlet in esecuzione sul server remoto


Mentre consentire il download di file via web è un’operazione estremamente facile grazie all'uso dei collegamenti ipertestuali, l’operazione opposta non è immediatamente messa a disposizione dall’HTML. Questo, del resto, è anche abbastanza ovvio, dal momento che nella suite TCP/IP, alla quale appartiene anche il protocollo http, per le operazioni di scambio di files esiste un protocollo apposito, detto appunto ftp

Per chi non lo sapesse, l’http (HyperText Transfer Protocol) è il protocollo di trasferimento di ipertesti, i files HTML, estesosi poi a protocollo per il trasferimento anche di tutti gli oggetti inglobati nelle pagine HTML, mentre l’ftp (File Transfer Protocol) è il protocollo specifico per le operazioni di movimentazione di files.
Mentre il trasferimento di oggetti ipertestuali (o meglio ipermediali) nell’http è inteso soltanto in un senso (dal server al client), per l’ftp lo spostamento di files puo’ avvenire in entrambi i versi.
Nonostante questa dichiarata e accettata differenza funzionale tra i due protocolli, esiste un tipo di campo HTML, inseribile nelle form, che consente la selezione di files dal file system dell’utente, ma l’operazione di salvataggio sul server deve essere implementata lato server. Tutto quello che l’http ci consente è l’invio di dati dal browser verso un U.R.L., ma non ci fornisce nessuna primitiva per l’interpretazione di tale evento come intenzione di trasferire files. Ancora una volta è Java che, diremmo quasi dal nulla, ci viene in aiuto per consentire quello che l’http neanche ha pensato.
In questo articolo vedremo come implementare un servlet Java per l’upload di files sul file system di un web server attraverso la compilazione di una form HTML da parte dell’utente.
Per procedere con un ordine, pero’, vediamo prima come, tramite Sevlet, sia possibile processare i dati normali inviati da una form HTML.
 
 
 

Invio dati dalla form al servlet
Prendiamo una semplice form HTML come quella dell’esempio che segue:

<FORM NAME=“THEFORM” METHOD=“GET” ACTION=“http://www.acme.com/servlet/regUser“
ENCTYPE=“application/www-urlencoded”>
First Name : <INPUT TYPE=“TEXT” NAME=“NAME”><BR>
Last Name : <INPUT TYPE=“TEXT” NAME=“SURNAME”><BR>
Profession : <INPUT TYPE=“TEXT” NAME=“PROFESSION”><BR>
Sex: <SELECT NAME=“SEX”>
  <OPTION VALUE=“M”>Male</OPTION>
<OPTION VALUE=“F”>Female</OPTION>
 </SELECT>
<INPUT TYPE=“RADIO” NAME=“CONTACTABLE” VALUE=“Y”> I want be contacted<BR>
<INPUT TYPE=“RADIO” NAME=“CONTACTABLE” VALUE=“N”> I don’t want be contacted<BR>
<INPUT TYPE=“SUBMIT” NAME=“SEND” VALUE=“Send”>
</FORM>

Si tratta di una form di registrazione a un qualche club, o ad una mailing list, o chissà cos’altro.
Nel momento in cui viene premuto il bottone di submit, i dati vengono inviati al servlet regUser.
Il servlet, da parte sua, recupera nomi e valori dei campi attraverso l’oggetto HttpServletRequest.
 

private void doGet(HttpServletRequest req, HttpServletResponse res)
{
 …
 String Name = req.getParameter(“NAME”);
 String Surname = req.getParameter(“SURNAME”);
 String Professione = req.getParameter(“PROFESSION”);
 String Sex = req.getParameter(“SEX”);
 String Contactable = req.getParameter(“CONTACTABLE”);
 …
}

Tale oggetto è sufficiente per parametri di tipo testo, ma nel caso di un file il procedimento da adottare deve essere diverso.
 
 
 

Invio file dalla form al servlet
Prima di tutto, se si vuole che dal client arrivino oltre che dati stringa anche files, occorrono delle modifiche nel codice HTML della form.
Tali modifiche interessano gli attributi METHOD e ENCTYPE.
Riscriviamo la form HTML nel modo corretto includendo il campo per la selezione di un file:

<FORM NAME=“THEFORM” METHOD=“POST” ACTION=“http://www.acme.com/servlet/regUser“
ENCTYPE=“multipart/form-data”>
First Name : <INPUT TYPE=“TEXT” NAME=“NAME”><BR>
Last Name : <INPUT TYPE=“TEXT” NAME=“SURNAME”><BR>
Profession : <INPUT TYPE=“TEXT” NAME=“PROFESSION”><BR>
Sex: <SELECT NAME=“SEX”>
  <OPTION VALUE=“M”>Male</OPTION>
<OPTION VALUE=“F”>Female</OPTION>
 </SELECT>
<INPUT TYPE=“RADIO” NAME=“CONTACTABLE” VALUE=“Y”> I want be contacted<BR>
<INPUT TYPE=“RADIO” NAME=“CONTACTABLE” VALUE=“N”> I don’t want be contacted<BR>
<INPUT TYPE=“FILE” NAME=“CURRICULUM” SIZE=15>
<INPUT TYPE=“SUBMIT” NAME=“SEND” VALUE=“Send”>
</FORM>

Quello che adesso ci serve lato servlet è una classe non standard in Java, ma presente nel package com.oreilly.servlet freeware e disponibile su Internet all’url http://www.servlets.com/resources/com.oreilly.servlet/index.html.
La classe da utilizzare è la MultipartRequest. 
Un oggetto MultipartRequest è simile all’HTTPServletRequest, ma capace di contenere contenente dati di diversa natura.
Il codice del servlet varia quindi in questo modo:

private void doPost(HttpServletRequest req, HttpServletResponse res)
{

 MultipartRequest multi = new MultipartRequest(req,".");
 String Name = multi.getParameter("NAME");
 String Surname = multi.getParameter("SURNAME");
 String Professione = multi.getParameter("PROFESSION");
 String Sex = multi.getParameter("SEX");
 String Contactable = multi.getParameter("CONTACTABLE");

 File f = multi.getFile("CURRICULUM");
 String fileName = multi.getFilesystemName("CURRICULUM");

}

Ora nel servlet abbiamo un oggetto di tipo File che possiamo utilizzare come vogliamo.
Parlando di una procedura di upload, quello che ci interessa è salvare tale file sul nostro file system.
A questo punto è pura programmazione Java:
 

 if (f!=null)
 {
File fOUT = new File("C:\\documents\\uploads\\",fileName)
 FileInputStream fIS = new FileInputStream(f);
 FileOutputStream fOS = new FileOutputStream(fOUT);
  while (fIS.available()>0)
   fOS.write(fIS.read());
 fIS.close();
 fOS.close();
}

In questo modo viene creato sul WebServer, nella directory c:\documents\uploads, una copia del file inviato dall’utente tramite il browser.
 
 
 

Un esempio di applicazione
Ora che abbiamo visto come funziona il tutto, prendiamo un esempio piu' concreto.
Immaginiamo di voler dare agli utenti del nostro sito la possibilità di gestire via Web una loro area, e quindi di poter loro far scaricare file HTML, immagini, applets etc. etc.
Un po' come funziona nei siti di Web Hosting tipo Tripod o Geocities.
 
 
 

Figura 1

 

Supponiamo che l'utente abbia già felicemente superato la procedura di riconoscimento e che  il path a lui assegnato come area web sia stata congelata in una variabile di sessione (Rif. 2) chiamata USER_PATH.
Il codice HTML per l'upload dei files (max 10) sarà:

<HTML>
<BODY BGCOLOR=YELLOW>
<FORM NAME="THEFORM" METHOD="POST" ACTION="http://www.acme.com/servlet/UplFile"
ENCTYPE="multipart/form-data">
<CENTER>
<font face=Arial>
<font size=+2 color=red>Seleziona i files da inviare</font><p>
File  1: <INPUT TYPE="FILE" NAME="File_1" SIZE=15><br>
File  2: <INPUT TYPE="FILE" NAME="File_2" SIZE=15><br>
File  3: <INPUT TYPE="FILE" NAME="File_3" SIZE=15><br>
File  4: <INPUT TYPE="FILE" NAME="File_4" SIZE=15><br>
File  5: <INPUT TYPE="FILE" NAME="File_5" SIZE=15><br>
File  6: <INPUT TYPE="FILE" NAME="File_6" SIZE=15><br>
File  7: <INPUT TYPE="FILE" NAME="File_7" SIZE=15><br>
File  8: <INPUT TYPE="FILE" NAME="File_8" SIZE=15><br>
File  9: <INPUT TYPE="FILE" NAME="File_9" SIZE=15><br>
File 10: <INPUT TYPE="FILE" NAME="File_10" SIZE=15><p>
</font>
<INPUT TYPE="SUBMIT" VALUE="Invia" >&nbsp;
<INPUT TYPE="RESET" VALUE="Annulla" >
</CENTER>
</FORM>
</BODY>
</HTML>
 

A differenza dell’esempio precedente, ora i campi di tipo FILE sono più di uno.
Inoltre potrebbe non essere fisso il numero di file massimo inviabili dall’utente in quanto la form potrebbe essere a sua volta generata dinamicamente da un servlet o dauna JSP.
Quindi il nostro servlet dovrà recuperare dall’oggetto MultipartRequest una collezione di files, anzi che uno:

private void doPost(HttpServletRequest req, HttpServletResponse res){
HttpSession session= req.getSession(true);
String User_Path = (String)session.getValue("USER_PATH");
MultipartRequest multi = new MultipartRequest(req,".");
Enumeration files = multi.getFileNames(); //Collezione di files
// inviati con la form
while (files.hasMoreElements()) {
String name = (String)files.nextElement();
File f = multi.getFile(name);
String fileName = multi.getFilesystemName(name);
if (f!=null){
  File fOUT = new File(User_Path,fileName);
  FileInputStream fIS = new FileInputStream(f);
  FileOutputStream fOS = new FileOutputStream(fOUT);
  while (fIS.available()>0)
     fOS.write(fIS.read());
  fIS.close();
  fOS.close();
 }
 }
}

Da questo momento in poi il lavoro del nostro utente sarà on-line, sempre a patto che questi abbia fatto un buon lavoro.
 
 
 

Conclusioni
I Web Server attualmente in circolazione (Apache, IIS, Netscape, etc.), tra i vari servizi, hanno anche un tool di Web Authoring nativo (Directory Services). L’implementazione ex novo di una procedura di upload via Web, quindi, potrebbe essere giustificata laddove quello che si richiede non è un banale trasferimento di files, bensi’ l’elaborazione (parsing) di dati inviati tramite file.
Per esempio, non volendoci discostare dall’esempio precedente, se si volesse dare all’utente la possibilità di comprimere tutti i files in un solo archivio in modo da inviare tramite upload un solo file, saremmo costretti ad implementare una procedura lato server (servlet) che decomprima l’archivio e copi i files in esso contenuti sul file system, magari rispettando i percorsi relativi (path) riportati nel file compresso.
Non ci dilunghiamo nell’illustrare come realizzare una magia del genere, limitandoci a citare il package java.util.zip, che contiene le classi per creare archivi zippati e estrarre da esso i singoli file. 
Attraverso l’uso combinato dei package com.oreilly.servlet e java.util.zip, quindi, si riesce a realizzare un servizio di Web Authoring  avanzato e veloce.
Per qualsiasi approfondimento, al già citato sito http://www.servlets.com/resources/com.oreilly.servlet/index.html è disponibile, oltre che il package con i sorgenti delle classi, anche una documentazione dettagliata. Intento del nostro articolo era solo quello di mostrare come, anche per questo problema, la tecnologia Servlet, o meglio il linguaggio Java, contrariamente a quanto si pensi rappresenti una delle soluzioni più complete e performanti per la realizzazione di applicazioni Web.
 
 
 

Bibliografia

1. Java Servlet Programming – Jason Hunter with William Crawford – 1998 O’Reilly
2. Gestire le sessioni con le Servlet – Gerardo Poggiali – Mokabyte n. 26, gennaio 1999

Ferdi Carcavallo è un Ingegnere Informatico napoletano che si occupa di Applicazioni Web di Document Management. E’ gentile e garbato, per cui può essere tranquillamente contattato all'indirizzo ferdi.carcavallo@libero.it. 


MokaByte rivista web su Java
MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it