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" >
<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. |