DownloadServlet – util pentru aplicatii web
Aproape orice aplicatie web are nevoie si de o optiune de Download care sa fie accesibila vizitatorilor site-ului si nu numai. O sa prezint o clasa realizata de mine, de fapt un servlet, ce implementeaza o operatie de download.
Acest servlet va primi 2 parametri : output ce reprezinta numele fisierului .zip generat si file (daca se downloadeaza un singur fisier) sau dir(daca trebuie luate toate fisierele dintr-un director). Indiferent de ce fisiere sunt trimise spre download, se creeaza un fisier .zip temporar care este trimis catre download.
In sectiunea download a acestui articol se gasesc 2 arhive, una continand codul sursa si cealalta contine arhiva .war ce poate fi utilizata out-of-the-box.
Ce veti gasi in acest servlet?
Pentru inceput 2 metode, doGet si doPost, despre care se poate spune ca trebuie sa existe in orice servlet. Pentru acest servlet de download, aceste 2 metode pot fi inlocuite cu success de metoda service.
protected void doPost(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse res) throws javax.servlet.ServletException, java.io.IOException
{
doGet(req, res);
}protected void doGet(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse res) throws javax.servlet.ServletException, java.io.IOException
{
this.outputFileName = req.getParameter(“output”);this.fileToDownload = req.getParameter(“file”);
this.dirToDownload = req.getParameter(“dir”);
processResponse(req, res);
}
Dupa cum se poate observa, metoda doPost doar apeleaza metoda doGet. Aceasta din urma preia parametrii trimisi catre servlet si initiza procesul de download prin metoda processResponse.
private boolean processResponse(HttpServletRequest req,
HttpServletResponse res)
{
File tmpZip = null;
Throwable th = null;try
{
tmpZip = new File(TMP_DIR
+ File.separator + Calendar.getInstance().getTimeInMillis() +TMP_PREFIX);this.createTmpZipFile(tmpZip);
this.download(res, tmpZip);return true;
}catch (Exception e)
{
th = e;
}finally
{
DownloadServlet.deleteFile(tmpZip);
}if (th != null)
{
log(“Error while processing the download request: “, th);
}return false;
}
Metoda ProcessResponse creaza fisierul .zip temporar sub numele %current_time%.zip, unde %current_time% reprezinta timpul curent in milisecunde.
Dupa ce fisierul zip temporar a fost creat, se scriu toate fisirele care au fost cerute pentru download.
private void createTmpZipFile(File tmpFile)
throws Exception
{
FileOutputStream zipFile = null;
ZipOutputStream outZip = null;try
{
zipFile = new FileOutputStream(tmpFile);
outZip = new ZipOutputStream(zipFile);if (this.fileToDownload != null)
this.addFile2Zip(outZip, new File(fileToDownload));
if (this.dirToDownload != null)
this.addFiles2ZipFromDir(outZip, dirToDownload);
}catch (FileNotFoundException e)
{
throw e;
}finally
{
outZip.close();
zipFile.close();
}
}
Prin createTmpZipFile se stabileste continutul fisierul .zip ce va fi trimis ca raspuns catre browser. Aceasta metoda scrie in fisierul temporar toate fisierele care au fost solicitate. In cazul in care exista ambii parametri, file si dir, atunci arhiva zip va contine toate fisierele din directorul trimis ca parametru, dar si fiserul care a fost solicitat.
Parametrii file si dir nu se exclud unul pe celalalt.
private void download(HttpServletResponse res, File zipFile)
throws Exception
{
OutputStream outStream = null;
FileInputStream fis = null;Throwable th = null;
try
{
this.setResponseContent(res, (int) zipFile.length());outStream = res.getOutputStream();
fis = new FileInputStream(zipFile);DownloadServlet.copyStream(fis, outStream);
outStream.flush();
return;
}catch (IOException e)
{
th = e;
}catch (Exception e)
{
th = e;
}finally
{
outStream.close();
fis.close();
}throw new Exception(“Error on download: “, th);
}
Metoda download trimite fisierul zip nou creat ca si raspuns la cererea primita. In aceasta metoda se deschide un stream de scriere in care se copiaza, in mod binar, fisierul zip arhivat.
In codul sursa atasat la articol veti mai gasi cateva metode pe care nu le-am explicat aici, deoarece consider ca sunt usor de inteles.
Recomandari
1) Implementarea unei metode de validare a fisierelor ce vor fi arhivate. Asa cum este creat acum servletul, se poate prelua orice fisier sau director de pe sistem daca se trimite toata calea. De exemplu, apelul linkului
http://%server%/downloadServlet/servlet/download?output=win&dir=D:\config va crea un fisier win.zip ce va contine toate fisirele din directorul D:\config.
2) Modificarea metodelor necesare astfel incat sa fie acceptati mai multi parametri cu numele “file” sau “dir“. Metodele ce trebuie modificate sunt doGet si createTmpZipFile.
3) Modificare addFiles2ZipFromDir astfel incat fisierul zip destinatie sa contina structura recursiva a directorului.
4) Adaugarea unei clase DownloadException care sa fie folosita la metodele createTmpZipFile, download, copyStream, addFiles2ZipFromDir,addFile2Zip
Download