Servlet Upload File y Download File es una tarea común en aplicaciones web Java. Dado que he escrito mucho sobre Servlets Java recientemente, pensé en proporcionar un ejemplo práctico de carga de archivos al servidor y luego descargarlos del servidor al cliente.
Cargar Archivo con Servlet
Nuestro caso de uso consiste en proporcionar una página HTML simple donde el cliente puede seleccionar un archivo local para cargarlo en el servidor. Al enviar la solicitud para cargar el archivo, nuestro programa servlet cargará el archivo en un directorio en el servidor y luego proporcionará la URL a través de la cual el usuario puede descargar el archivo. Por razones de seguridad, al usuario no se le proporcionará la URL directa para descargar el archivo; en cambio, se le dará un enlace para descargar el archivo, y nuestro servlet procesará la solicitud y enviará el archivo al usuario. Crearemos un proyecto web dinámico en Eclipse y la estructura del proyecto se verá como en la siguiente imagen. Examinemos todos los componentes de nuestra aplicación web y comprendamos la implementación.
Página HTML para Subir Archivos a un Servidor Java
Podemos cargar un archivo en el servidor enviando una solicitud POST al servlet y enviando el formulario. No podemos utilizar el método GET para cargar un archivo. Otro punto a tener en cuenta es que el atributo enctype del formulario debe ser multipart/form-data. Para seleccionar un archivo del sistema de archivos del usuario, necesitamos usar el elemento input con type como file. Así que podemos tener una página HTML simple llamada index.html para cargar archivos, de la siguiente manera:
<html>
<head></head>
<body>
<form action="UploadDownloadFileServlet" method="post" enctype="multipart/form-data">
Select File to Upload:<input type="file" name="fileName">
<br>
<input type="submit" value="Upload">
</form>
</body>
</html>
Ruta del Archivo en el Servidor para la Carga de Archivos
Necesitamos almacenar el archivo en algún directorio en el servidor. Podemos tener este directorio codificado en el programa, pero para una mejor flexibilidad, lo mantendremos configurable en los parámetros de contexto del descriptor de implementación. También agregaremos nuestra página HTML de carga de archivos a la lista de archivos de bienvenida. Nuestro archivo web.xml se verá así:
<?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>ServletFileUploadDownloadExample</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>tempfile.dir</param-name>
<param-value>tmpfiles</param-value>
</context-param>
</web-app>
ServletContextListener para la Ubicación de Carga de Archivos
Dado que necesitamos leer el parámetro de contexto para la ubicación del archivo y crear un objeto File a partir de él, podemos escribir un ServletContextListener para hacerlo cuando se inicialice el contexto. Podemos establecer la ubicación del directorio absoluto y el objeto File como atributo de contexto para ser utilizado por otros servlets. Nuestro código de implementación del ServletContextListener es como se muestra a continuación.
package com.journaldev.servlet;
import java.io.File;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class FileLocationContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
String rootPath = System.getProperty("catalina.home");
ServletContext ctx = servletContextEvent.getServletContext();
String relativePath = ctx.getInitParameter("tempfile.dir");
File file = new File(rootPath + File.separator + relativePath);
if(!file.exists()) file.mkdirs();
System.out.println("File Directory created to be used for storing files");
ctx.setAttribute("FILES_DIR_FILE", file);
ctx.setAttribute("FILES_DIR", rootPath + File.separator + relativePath);
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
// hacer limpieza si es necesario
}
}
Servidor de carga y descarga de archivos
Actualizar: La especificación de Servlet 3 agregó soporte para cargar archivos en el servidor en la API, por lo que no necesitaremos utilizar ninguna API de terceros. Por favor, revisa Servlet 3 Subir Archivo. Para la carga de archivos, utilizaremos la utilidad Apache Commons FileUpload; para nuestro proyecto, estamos utilizando la versión 1.3. FileUpload depende de la biblioteca Apache Commons IO, así que necesitamos colocar ambas en el directorio “lib” del proyecto, como se muestra en la imagen anterior de la estructura del proyecto. Utilizaremos la factoría DiskFileItemFactory, que proporciona un método para analizar el objeto HttpServletRequest y devolver una lista de FileItem. FileItem proporciona métodos útiles para obtener el nombre del archivo, el nombre del campo en el formulario, el tamaño y los detalles del tipo de contenido del archivo que se va a cargar. Para escribir el archivo en un directorio, todo lo que necesitamos hacer es crear un objeto File y pasarlo como argumento al método write() de FileItem. Dado que el propósito principal del servlet es cargar un archivo, anularemos el método init() para inicializar la instancia del objeto DiskFileItemFactory
del servlet. Utilizaremos este objeto en la implementación del método doPost() para cargar el archivo en el directorio del servidor. Una vez que el archivo se haya cargado correctamente, enviaremos una respuesta al cliente con la URL para descargar el archivo. Dado que los enlaces HTML utilizan el método GET, añadiremos el parámetro del nombre del archivo en la URL y podremos utilizar el mismo método doGet() del servlet para implementar el proceso de descarga de archivos. Para implementar el servlet de descarga de archivos, primero abriremos el InputStream para el archivo y utilizaremos el método ServletContext.getMimeType() para obtener el tipo MIME del archivo y establecerlo como el tipo de contenido de la respuesta. También necesitaremos establecer la longitud del contenido de la respuesta como la longitud del archivo. Para asegurarnos de que el cliente entienda que estamos enviando un archivo en la respuesta, debemos establecer la cabecera “Content-Disposition” con el valor “attachment; filename=“fileName”. Una vez que hayamos configurado la respuesta, podemos leer el contenido del archivo desde InputStream y escribirlo en ServletOutputStream, y luego enviar la salida al cliente. Nuestra implementación final del servlet UploadDownloadFileServlet se ve así.
package com.journaldev.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@WebServlet("/UploadDownloadFileServlet")
public class UploadDownloadFileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private ServletFileUpload uploader = null;
@Override
public void init() throws ServletException{
DiskFileItemFactory fileFactory = new DiskFileItemFactory();
File filesDir = (File) getServletContext().getAttribute("FILES_DIR_FILE");
fileFactory.setRepository(filesDir);
this.uploader = new ServletFileUpload(fileFactory);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String fileName = request.getParameter("fileName");
if(fileName == null || fileName.equals("")){
throw new ServletException("File Name can't be null or empty");
}
File file = new File(request.getServletContext().getAttribute("FILES_DIR")+File.separator+fileName);
if(!file.exists()){
throw new ServletException("File doesn't exists on server.");
}
System.out.println("File location on server::"+file.getAbsolutePath());
ServletContext ctx = getServletContext();
InputStream fis = new FileInputStream(file);
String mimeType = ctx.getMimeType(file.getAbsolutePath());
response.setContentType(mimeType != null? mimeType:"application/octet-stream");
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
ServletOutputStream os = response.getOutputStream();
byte[] bufferData = new byte[1024];
int read=0;
while((read = fis.read(bufferData))!= -1){
os.write(bufferData, 0, read);
}
os.flush();
os.close();
fis.close();
System.out.println("File downloaded at client successfully");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(!ServletFileUpload.isMultipartContent(request)){
throw new ServletException("Content type is not multipart/form-data");
}
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.write("<html><head></head><body>");
try {
List<FileItem> fileItemsList = uploader.parseRequest(request);
Iterator<FileItem> fileItemsIterator = fileItemsList.iterator();
while(fileItemsIterator.hasNext()){
FileItem fileItem = fileItemsIterator.next();
System.out.println("FieldName="+fileItem.getFieldName());
System.out.println("FileName="+fileItem.getName());
System.out.println("ContentType="+fileItem.getContentType());
System.out.println("Size in bytes="+fileItem.getSize());
File file = new File(request.getServletContext().getAttribute("FILES_DIR")+File.separator+fileItem.getName());
System.out.println("Absolute Path at server="+file.getAbsolutePath());
fileItem.write(file);
out.write("File "+fileItem.getName()+ " uploaded successfully.");
out.write("<br>");
out.write("<a href=\"UploadDownloadFileServlet?fileName="+fileItem.getName()+"\">Download "+fileItem.getName()+"</a>");
}
} catch (FileUploadException e) {
out.write("Exception in uploading file.");
} catch (Exception e) {
out.write("Exception in uploading file.");
}
out.write("</body></html>");
}
}
La ejecución de muestra del proyecto se muestra en las siguientes imágenes.
Descargar Archivo Servlet Subir Proyecto de Descarga
Puedes descargar el archivo jar de Apache Commons IO y el archivo jar de Apache Commons FileUpload desde las siguientes URL. https://commons.apache.org/proper/commons-fileupload/download_fileupload.cgi https://commons.apache.org/proper/commons-io/download_io.cgi
Descargar Archivo Servlet Subir Proyecto de Ejemplo de Descarga
¡Echa un vistazo al próximo artículo de la serie sobre Manejo de Excepciones de Servlet!
Source:
https://www.digitalocean.com/community/tutorials/servlet-upload-file-download-example