Você está na página 1de 7

Como fazer upload e download de arquivos usando Servlet e JSP

Link: http://andvicoso.blogspot.pt/2013/02/como-fazer-upload-edownload-de.html
Este post vai apresentar como implementar um upload e download de arquivos usando Servlets, JSP, JSTL, EL e o padro MVC. Para este exemplo, vou criar um projeto web dinmico no Eclipse. Eu no vou especificar um banco de dados, o cdigo deve funcionar com qualquer banco relacional. Para implementar o exemplo precisamos de quatro bibliotecas adicionais, sendo duas da Apache:

http://commons.apache.org/fileupload/ http://commons.apache.org/io

E para usar o JSTL precisamos de mais duas bibliotecas adicionais, a API e a implementao. Ambos podem ser encontrados no link:

http://jstl.java.net/download.html

Baixe todas as bibliotecas e adicione na pasta lib dentro de WebContent. A pasta lib tambm deve conter o conector para o banco de dados utilizado.

Upload
A pgina de envio deve conter um formulrio com os campos necessrios e mais um campo de input type file para o upload. No exemplo a seguir, vou mostrar o formulrio com apenas dois campos: input type="file" e outro input type="text".
<form action="upload.do" enctype="multipart/form-data" method="post"> <label for="desc">Descrio:</label> <input type="text" name="desc" id="desc"><br/> <label for="file">Arquivo:</label> <input type="file" name="file" id="file"><br/> <input type="submit" value="Enviar"/> </form>

A servlet que vai receber os dados deste formulrio deve conter o cdigo:
public class UploadFileServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { DiskFileItemFactory dfif = new DiskFileItemFactory(); ServletFileUpload sfu = new ServletFileUpload(dfif);

if (!ServletFileUpload.isMultipartContent(req)) { // tratar erro } try { List items = sfu.parseRequest(req); //a posicao 0 corresponde ao primeiro campo input do formulario (descricao) FileItem descFI = (FileItem) items.get(0); String desc = descFI.getString(); //a posicao 1 corresponde ao segundo campo input do formulario (arquivo) FileItem fileFI = (FileItem) items.get(1); byte[] bytes = read(fileFI); //No o File do Java. um JavaBean apresentado a seguir FileBean filebean = new FileBean(); filebean.setDescription(fileFI.getDesc()); filebean.setName(fileFI.getName()); filebean.setData(bytes); FileDao fdao = new FileDaoImpl(); fdao.add(filebean); } catch (FileUploadException e) { // tratar erro } resp.sendRedirect("list.jsp"); } private byte[] read(FileItem fi) throws IOException{ ByteArrayOutputStream out = new ByteArrayOutputStream(); InputStream is = fi.getInputStream(); int read = 0; final byte[] b = new byte[1024]; while ((read = is.read(b)) != -1) { out.write(b, 0, read); } return out.toByteArray(); } }

Para verificar se um FileItem um campo do comum formulrio ou um campo (input) do tipo file, podemos usar o mtodo: fileItem.isFormField(). No se esquea de mapear a sua servlet (UploadFileServlet)! Pode ser mapeada usando anotaes (API Servlet 3.x) ou com o bom e velho deployment descriptor (web.xml). Segue o trecho do web.xml correspondente:
<servlet> <servlet-name>UploadFileServlet</servlet-name> <servletclass>controller.user.file.UploadFileServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadFileServlet</servlet-name>

<url-pattern>/upload.do</url-pattern> </servlet-mapping>

No cdigo acima a classe da servlet se encontra no pacote controller.user.file , altere para o caminho correto dentro da sua aplicao. A servlet UploadFileServlet faz uso da classe JavaBean FileBean, com o cdigo:
public class FileBean { private String description; private String name; private Long id; private byte[] data; public FileBean() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public byte[] getData() { return data; } public void setData(byte[] data) { this.data = data; } }

Para armazenar o cdigo no banco de dados temos que ter uma tabela que corresponda ao arquivo. Essa tabela deve conter um varchar para o nome, outro para a descrio, um campo blob para o arquivo (bytes) e um campo id para identificar cada arquivo adicionado. Devemos setar esse ltimo campo como autoincrement (MySQL). O cdigo da DAO que armazena os dados, lista e busca o JavaBean (FileBean) no banco de dados :

public boolean add(FileBean filebean) { int added = 0; try { Connection con = ConnectionFactory.createConnection(); if (con != null) { String sql = "INSERT INTO file (name, description, data) VALUES (?, ?, ?)"; PreparedStatement st = con.prepareStatement(sql); st.setString(1, filebean.getName()); st.setString(2, filebean.getDescription()); st.setBytes(3, filebean.getData()); added = st.executeUpdate(); st.close(); con.close(); } } catch (SQLException e) { //tratar erro } return added > 0; } public List list() { List files = new ArrayList(); try { Connection con = ConnectionFactory.createConnection(); if (con != null) { String sql = "SELECT * FROM file"; Statement st = con.createStatement(); ResultSet rs = st.execute(sql); while(rs.next()){ FileBean filebean = createFileBean(rs); files.add(filebean); } st.close(); con.close(); } } catch (SQLException e) { //tratar erro } return files; } public FileBean getFile(long id) { FileBean filebean = null; try { Connection con = ConnectionFactory.createConnection(); if (con != null) { String sql = "SELECT * FROM file WHERE id=?"; PreparedStatement st = con.prepareStatement(sql); st.setLong(1, id); ResultSet rs = st.executeQuery(); if (rs.next()) { filebean = createFileBean(rs); } rs.close(); st.close(); con.close();

} } catch (SQLException e) { e.printStackTrace(); } return file; } private FileBean createFileBean(ResultSet rs) throws SQLException { FileBean filebean = new FileBean(); filebean.setData(rs.getBytes("data")); filebean.setId(rs.getLong("id")); filebean.setName(rs.getString("name")); filebean.setDescription(rs.getString("description")); return filebean; }

Os mtodos da DAO fazem chamada a um mtodo da classe ConnectionFactory que apenas cria e retorna uma conexo ao banco de dados. Daqui j podemos executar pra testar!

Download
Para o download vou mostrar um trecho de cdigo de um JSP (list.jsp) que lista os arquivos do banco de dados e ao clicar sobre um arquivo o download iniciado. Este cdigo faz uso do JSTL e da EL. Se for uma imagem ele mostra um thumbnail ao invs do boto de download.
<table> <thead> <tr> <th align="center"><b>Nome</b></th> <th align="center"><b>Descrio</b></th> <th align="center"><b>Arquivo</b></th> </tr> </thead> <tbody> <c:forEach var="file" items="${items}"> <c:set value="${fn:endsWith(file.name, 'jpg') or fn:endsWith(file.name, 'png')}" var="isImage"/> <tr> <td>${file.name}</td> <td>${file.description}</td> <c:if test="${isImage}"> <td><img width="50" height="50" src="download.do?id=${file.id}"/></td> </c:if> <c:if test="${not isImage}"> <td><a href="download.do?id=${file.id}">Baixar</a></td> </c:if> </tr> </c:forEach> </tbody> </table>

A servlet que busca os arquivos na base de dados tem o cdigo:


public class ListFilesServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { FileDao dao = new FileDaoImpl(); List<FileBean> files = dao.list(); req.setAttribute("items", dao.list()); RequestDispatcher rd = pReq.getRequestDispatcher("list.jsp"); rd.forward(req, resp); } }

A classe da servlet responsvel pelo download tem o cdigo:


public class DownloadFileServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String idStr = req.getParameter("id"); if(idStr == null){ //redirect to home or other } FileDao dao = new FileDaoImpl(); Long id = Long.parseLong(idStr); FileBean filebean = dao.getFile(id); if (file != null) { ServletContext context = getServletConfig().getServletContext(); String mimetype = context.getMimeType(filebean.getName()); resp.setContentLength(filebean.getData().length); resp.setContentType(mimetype);//resp.setContentType("image/jpeg"); resp.setHeader("Content-Disposition", "attachment; filename=\"" + filebean.getName() + "\""); OutputStream out = resp.getOutputStream(); InputStream in = new ByteArrayInputStream(filebean.getData()); byte[] buffer = new byte[4096]; int length; while ((length = in.read(buffer)) > 0) { out.write(buffer, 0, length); } in.close(); out.flush(); } }

Elas tambm devem ser mapeadas, tal como no exemplo a seguir:


<servlet> <servlet-name>DownloadFileServlet</servlet-name> <servletclass>controller.user.file.DownloadFileServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DownloadFileServlet</servlet-name> <url-pattern>/download.do</url-pattern> </servlet-mapping> <servlet> <servlet-name>ListFilesServlet</servlet-name> <servlet-class>controller.user.file.ListFilesServlet</servletclass> </servlet> <servlet-mapping> <servlet-name>ListFilesServlet</servlet-name> <url-pattern>/list.do</url-pattern> </servlet-mapping>

Acho que isso. Se tiver algum erro, melhoria ou dificuldade na implementao s avisar! Happy coding! []`s