Pregunta ¿Cómo subir archivos al servidor usando JSP / Servlet?


¿Cómo puedo subir archivos al servidor usando JSP / Servlet? Intenté esto:

<form action="upload" method="post">
    <input type="text" name="description" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

Sin embargo, solo obtengo el nombre del archivo, no el contenido del archivo. Cuando agrego enctype="multipart/form-data" al <form>, entonces request.getParameter() devoluciones null.

Durante la investigación tropecé con Apache Common FileUpload. Intenté esto:

FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List items = upload.parseRequest(request); // This line is where it died.

Desafortunadamente, el servlet arrojó una excepción sin un mensaje claro y una causa. Aquí está la stacktrace:

SEVERE: Servlet.service() for servlet UploadServlet threw exception
javax.servlet.ServletException: Servlet execution threw an exception
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:313)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    at java.lang.Thread.run(Thread.java:637)

609
2018-03-11 04:07


origen


Respuestas:


Introducción

Para navegar y seleccionar un archivo para subir necesita un HTML <input type="file"> campo en la forma. Como se indica en el Especificación de HTML tienes que usar el POST método y el enctype atributo de la forma debe configurarse para "multipart/form-data".

<form action="upload" method="post" enctype="multipart/form-data">
    <input type="text" name="description" />
    <input type="file" name="file" />
    <input type="submit" />
</form>

Después de enviar un formulario de este tipo, los datos del formulario binario multiparte están disponibles en el cuerpo de la solicitud en un formato diferente que cuando el enctype no está configurado.

Antes de Servlet 3.0, la API de Servlet no era compatible nativamente multipart/form-data. Solo admite el tipo de formulario predeterminado de application/x-www-form-urlencoded. los request.getParameter() y las consortes regresarían todas null cuando se usan datos de formulario multiparte. Aquí es donde el conocido Apache Commons FileUpload entró en la imagen.

¡No lo analice manualmente!

En teoría, puede analizar el cuerpo de la solicitud basándose en ServletRequest#getInputStream(). Sin embargo, este es un trabajo preciso y tedioso que requiere un conocimiento preciso de RFC2388. No intente hacer esto por su cuenta o copie un código de biblioteca local que se encuentre en otra parte de Internet. Muchas fuentes en línea han fracasado mucho en esto, como roseindia.net. Ver también carga de archivo pdf. Debería utilizar una biblioteca real que millones (millones de usuarios) utilizan (¡e implícitamente probaron!) Durante años. Tal biblioteca ha demostrado su robustez.

Cuando ya esté en Servlet 3.0 o posterior, use la API nativa

Si está utilizando al menos Servlet 3.0 (Tomcat 7, Jetty 9, JBoss AS 6, GlassFish 3, etc.), puede usar API estándar proporcionada HttpServletRequest#getPart() para recopilar los elementos de datos de formulario multiparte individuales (¡la mayoría de las implementaciones de Servlet 3.0 realmente usan Apache Commons FileUpload bajo las cubiertas para esto!). Además, los campos de formulario normales están disponibles por getParameter() la forma habitual.

Primero anote su servlet con @MultipartConfig para permitirle reconocer y apoyar multipart/form-data solicitudes y así obtener getPart() trabajar:

@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
    // ...
}

Entonces, implementa su doPost() como sigue:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String description = request.getParameter("description"); // Retrieves <input type="text" name="description">
    Part filePart = request.getPart("file"); // Retrieves <input type="file" name="file">
    String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
    InputStream fileContent = filePart.getInputStream();
    // ... (do your job here)
}

Nota la Path#getFileName(). Esta es una solución de MSIE para obtener el nombre del archivo. Este navegador envía incorrectamente la ruta completa del archivo a lo largo del nombre en lugar de solo el nombre del archivo.

En caso de que tengas un <input type="file" name="file" multiple="true" /> para la carga de varios archivos, recógelos de la siguiente manera (desafortunadamente no existe un método como request.getParts("file"))

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // ...
    List<Part> fileParts = request.getParts().stream().filter(part -> "file".equals(part.getName())).collect(Collectors.toList()); // Retrieves <input type="file" name="file" multiple="true">

    for (Part filePart : fileParts) {
        String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
        InputStream fileContent = filePart.getInputStream();
        // ... (do your job here)
    }
}

Cuando aún no está en Servlet 3.1, obtenga manualmente el nombre del archivo enviado

Tenga en cuenta que Part#getSubmittedFileName() se introdujo en Servlet 3.1 (Tomcat 8, Jetty 9, WildFly 8, GlassFish 4, etc.). Si todavía no está en Servlet 3.1, necesita un método de utilidad adicional para obtener el nombre del archivo enviado.

private static String getSubmittedFileName(Part part) {
    for (String cd : part.getHeader("content-disposition").split(";")) {
        if (cd.trim().startsWith("filename")) {
            String fileName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
            return fileName.substring(fileName.lastIndexOf('/') + 1).substring(fileName.lastIndexOf('\\') + 1); // MSIE fix.
        }
    }
    return null;
}
String fileName = getSubmittedFileName(filePart);

Tenga en cuenta la corrección de MSIE en cuanto a la obtención del nombre del archivo. Este navegador envía incorrectamente la ruta completa del archivo a lo largo del nombre en lugar de solo el nombre del archivo.

Cuando aún no está en Servlet 3.0, use Apache Commons FileUpload

Si aún no está en Servlet 3.0 (¿no es hora de actualizar?), La práctica común es hacer uso de Apache Commons FileUpload para analizar las solicitudes de datos de formularios de varias partes. Tiene un excelente Guía del usuario y Preguntas más frecuentes (revise cuidadosamente ambos). También está el O'Reilly ("cos") MultipartRequest, pero tiene algunos errores (menores) y no se mantiene activamente durante años. No recomendaría usarlo. Apache Commons FileUpload aún se mantiene activamente y en la actualidad es muy maduro.

Para utilizar Apache Commons FileUpload, debe tener al menos los siguientes archivos en su webapp /WEB-INF/lib:

Tu intento inicial fracasó muy probablemente porque olvidaste el IO común.

Aquí hay un ejemplo inicial de cómo doPost() de tu UploadServlet puede parecerse a cuando se utiliza Apache Commons FileUpload:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
        for (FileItem item : items) {
            if (item.isFormField()) {
                // Process regular form field (input type="text|radio|checkbox|etc", select, etc).
                String fieldName = item.getFieldName();
                String fieldValue = item.getString();
                // ... (do your job here)
            } else {
                // Process form file field (input type="file").
                String fieldName = item.getFieldName();
                String fileName = FilenameUtils.getName(item.getName());
                InputStream fileContent = item.getInputStream();
                // ... (do your job here)
            }
        }
    } catch (FileUploadException e) {
        throw new ServletException("Cannot parse multipart request.", e);
    }

    // ...
}

Es muy importante que no llame getParameter(), getParameterMap(), getParameterValues(), getInputStream(), getReader(), etc. en la misma solicitud de antemano. De lo contrario, el contenedor de servlets leerá y analizará el cuerpo de la solicitud y, por lo tanto, Apache Commons FileUpload obtendrá un cuerpo de solicitud vacío. Ver también a.o. ServletFileUpload # parseRequest (solicitud) devuelve una lista vacía.

Nota la FilenameUtils#getName(). Esta es una solución de MSIE para obtener el nombre del archivo. Este navegador envía incorrectamente la ruta completa del archivo a lo largo del nombre en lugar de solo el nombre del archivo.

Alternativamente, también puede envolver todo esto en un Filter que analiza todo automágicamente y vuelve a colocar el material en el mapa de parámetros de la solicitud para que pueda continuar usando request.getParameter() de la manera habitual y recuperar el archivo cargado por request.getAttribute(). Puedes encontrar un ejemplo en este artículo de blog.

Solución del error GlassFish3 de getParameter() todavía regresando null

Tenga en cuenta que las versiones de Glassfish anteriores a 3.1.2 tenían un insecto Donde en el getParameter() aún regresa null. Si se dirige a dicho contenedor y no puede actualizarlo, debe extraer el valor de getPart() con la ayuda de este método de utilidad:

private static String getValue(Part part) throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), "UTF-8"));
    StringBuilder value = new StringBuilder();
    char[] buffer = new char[1024];
    for (int length = 0; (length = reader.read(buffer)) > 0;) {
        value.append(buffer, 0, length);
    }
    return value.toString();
}
String description = getValue(request.getPart("description")); // Retrieves <input type="text" name="description">

Guardar el archivo cargado (no usar getRealPath() ni part.write()!

Diríjase a las siguientes respuestas para obtener detalles sobre cómo guardar correctamente el InputStream (el fileContent variable como se muestra en los fragmentos de código anteriores) en el disco o la base de datos:

Sirviendo archivo cargado

Diríjase a las siguientes respuestas para obtener detalles sobre cómo servir correctamente el archivo guardado desde el disco o la base de datos al cliente:

Ajaxificar la forma

Dirígete a las siguientes respuestas sobre cómo subir usando Ajax (y jQuery). ¡Tenga en cuenta que no es necesario cambiar el código de servlet para recopilar los datos del formulario! Solo se puede cambiar la forma en que responde, pero esto es bastante trivial (es decir, en lugar de reenviar a JSP, simplemente imprima JSON o XML, o incluso texto sin formato, dependiendo de lo que el script responsable de la llamada Ajax esté esperando).


Espero que todo esto ayude :)


1072
2018-03-11 12:27



Si usa Spring MVC, esta es la forma de: (Voy a dejar esto aquí en caso de que alguien lo encuentre útil).

Use un formulario con enctype atributo establecido en "multipart/form-data"(Igual que la respuesta de BalusC)

<form action="upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" value="Upload"/>
</form>

En su controlador, mapee el parámetro de solicitud file a MultipartFile escriba de la siguiente manera:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public void handleUpload(@RequestParam("file") MultipartFile file) throws IOException {
    if (!file.isEmpty()) {
            byte[] bytes = file.getBytes(); // alternatively, file.getInputStream();
            // application logic
    }
}

Puedes obtener el nombre de archivo y el tamaño usando MultipartFilees getOriginalFilename() y getSize().

He probado esto con la versión de Spring 4.1.1.RELEASE.


24
2017-08-26 12:39



Necesitas el common-io.1.4.jar archivo para ser incluido en su lib directorio, o si está trabajando en cualquier editor, como NetBeans, entonces tiene que ir a las propiedades del proyecto y simplemente agregar el archivo JAR y habrá terminado.

Para obtener el common.io.jar archivar solo google o simplemente ir a Apache Gato sitio web donde tiene la opción de descargar gratis este archivo. Pero recuerde una cosa: descargue el archivo ZIP binario si usted es un usuario de Windows.


12
2018-05-17 11:11



Estoy usando Servlet común para cada Html Form si tiene archivos adjuntos o no. Este servlet devuelve un TreeMap donde las claves son jsp name Los parámetros y valores son User Inputs y guardan todos los archivos adjuntos en el directorio fijo y más adelante cambia el nombre del directorio de su elección. Here Connections es nuestra interfaz personalizada que tiene un objeto de conexión. Creo que esto te ayudará

public class ServletCommonfunctions extends HttpServlet implements
        Connections {

    private static final long serialVersionUID = 1L;

    public ServletCommonfunctions() {}

    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException,
            IOException {}

    public SortedMap<String, String> savefilesindirectory(
            HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        // Map<String, String> key_values = Collections.synchronizedMap( new
        // TreeMap<String, String>());
        SortedMap<String, String> key_values = new TreeMap<String, String>();
        String dist = null, fact = null;
        PrintWriter out = response.getWriter();
        File file;
        String filePath = "E:\\FSPATH1\\2KL06CS048\\";
        System.out.println("Directory Created   ????????????"
            + new File(filePath).mkdir());
        int maxFileSize = 5000 * 1024;
        int maxMemSize = 5000 * 1024;
        // Verify the content type
        String contentType = request.getContentType();
        if ((contentType.indexOf("multipart/form-data") >= 0)) {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // maximum size that will be stored in memory
            factory.setSizeThreshold(maxMemSize);
            // Location to save data that is larger than maxMemSize.
            factory.setRepository(new File(filePath));
            // Create a new file upload handler
            ServletFileUpload upload = new ServletFileUpload(factory);
            // maximum file size to be uploaded.
            upload.setSizeMax(maxFileSize);
            try {
                // Parse the request to get file items.
                @SuppressWarnings("unchecked")
                List<FileItem> fileItems = upload.parseRequest(request);
                // Process the uploaded file items
                Iterator<FileItem> i = fileItems.iterator();
                while (i.hasNext()) {
                    FileItem fi = (FileItem) i.next();
                    if (!fi.isFormField()) {
                        // Get the uploaded file parameters
                        String fileName = fi.getName();
                        // Write the file
                        if (fileName.lastIndexOf("\\") >= 0) {
                            file = new File(filePath
                                + fileName.substring(fileName
                                        .lastIndexOf("\\")));
                        } else {
                            file = new File(filePath
                                + fileName.substring(fileName
                                        .lastIndexOf("\\") + 1));
                        }
                        fi.write(file);
                    } else {
                        key_values.put(fi.getFieldName(), fi.getString());
                    }
                }
            } catch (Exception ex) {
                System.out.println(ex);
            }
        }
        return key_values;
    }
}

9
2018-01-08 05:50



Sin componentes o biblioteca externa en Tomcat 6 o 7

Habilitando Subir en el web.xml archivo:

http://joseluisbz.wordpress.com/2014/01/17/manually-installing-php-tomcat-and-httpd-lounge/#Enabling%20File%20Uploads.

<servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <multipart-config>
      <max-file-size>3145728</max-file-size>
      <max-request-size>5242880</max-request-size>
    </multipart-config>
    <init-param>
        <param-name>fork</param-name>
        <param-value>false</param-value>
    </init-param>
    <init-param>
        <param-name>xpoweredBy</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
</servlet>

COMO PUEDES VER:

    <multipart-config>
      <max-file-size>3145728</max-file-size>
      <max-request-size>5242880</max-request-size>
    </multipart-config>

Subiendo archivos usando JSP. Archivos:

En el archivo html

<form method="post" enctype="multipart/form-data" name="Form" >

  <input type="file" name="fFoto" id="fFoto" value="" /></td>
  <input type="file" name="fResumen" id="fResumen" value=""/>

En el archivo JSP o Servlet

    InputStream isFoto = request.getPart("fFoto").getInputStream();
    InputStream isResu = request.getPart("fResumen").getInputStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte buf[] = new byte[8192];
    int qt = 0;
    while ((qt = isResu.read(buf)) != -1) {
      baos.write(buf, 0, qt);
    }
    String sResumen = baos.toString();

Edite su código a los requisitos del servlet, como Tamaño máximo de archivo, max-request-size  y otras opciones que puedes configurar ...


7
2018-01-25 05:44



Para Spring MVC He estado intentando durante horas hacer esto y se las arregló para tener una versión más simple que funcionó para tomar la forma de entrada tanto de datos como de imágenes.

<form action="/handleform" method="post" enctype="multipart/form-data">
  <input type="text" name="name" />
  <input type="text" name="age" />
  <input type="file" name="file" />
  <input type="submit" />
</form>

Controlador para manejar

@Controller
public class FormController {
    @RequestMapping(value="/handleform",method= RequestMethod.POST)
    ModelAndView register(@RequestParam String name, @RequestParam int age, @RequestParam MultipartFile file)
            throws ServletException, IOException {

        System.out.println(name);
        System.out.println(age);
        if(!file.isEmpty()){
            byte[] bytes = file.getBytes();
            String filename = file.getOriginalFilename();
            BufferedOutputStream stream =new BufferedOutputStream(new FileOutputStream(new File("D:/" + filename)));
            stream.write(bytes);
            stream.flush();
            stream.close();
        }
        return new ModelAndView("index");
    }
}

Espero eso ayude :)


7
2017-07-15 19:42



Otra fuente de este problema ocurre si está utilizando Geronimo con su Tomcat integrado. En este caso, después de muchas iteraciones de prueba commons-io y commons-fileupload, el problema surge de un cargador de clases padre que maneja los archivos commons-xxx. Esto debe ser prevenido. El bloqueo siempre se produjo en:

fileItems = uploader.parseRequest(request);

Tenga en cuenta que el tipo de List de fileItems ha cambiado con la versión actual de commons-fileupload para ser específicamente List<FileItem>a diferencia de versiones anteriores donde era genérico List.

Agregué el código fuente para commons-fileupload y commons-io en mi proyecto de Eclipse para rastrear el error real y finalmente obtuve algo de información. En primer lugar, la excepción lanzada es de tipo Throwable no la FileIOException establecida ni incluso Exception (no quedarán atrapadas). En segundo lugar, el mensaje de error es ofuscante en el sentido de que no se encontró una clase porque axis2 no pudo encontrar commons-io. Axis2 no se usa en absoluto en mi proyecto, pero existe como una carpeta en el subdirectorio del repositorio Geronimo como parte de la instalación estándar.

Finalmente, encontré 1 lugar que planteó una solución de trabajo que resolvió mi problema con éxito. Debe ocultar los archivos jar del cargador principal en el plan de despliegue. Esto se puso en geronimo-web.xml con mi archivo completo que se muestra a continuación.

Pasted from <http://osdir.com/ml/user-geronimo-apache/2011-03/msg00026.html> 



<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<web:web-app xmlns:app="http://geronimo.apache.org/xml/ns/j2ee/application-2.0" xmlns:client="http://geronimo.apache.org/xml/ns/j2ee/application-client-2.0" xmlns:conn="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2" xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2" xmlns:ejb="http://openejb.apache.org/xml/ns/openejb-jar-2.2" xmlns:log="http://geronimo.apache.org/xml/ns/loginconfig-2.0" xmlns:name="http://geronimo.apache.org/xml/ns/naming-1.2" xmlns:pers="http://java.sun.com/xml/ns/persistence" xmlns:pkgen="http://openejb.apache.org/xml/ns/pkgen-2.1" xmlns:sec="http://geronimo.apache.org/xml/ns/security-2.0" xmlns:web="http://geronimo.apache.org/xml/ns/j2ee/web-2.0.1">
    <dep:environment>
        <dep:moduleId>
            <dep:groupId>DataStar</dep:groupId>
            <dep:artifactId>DataStar</dep:artifactId>
            <dep:version>1.0</dep:version>
            <dep:type>car</dep:type>
        </dep:moduleId>

<!--Don't load commons-io or fileupload from parent classloaders-->
        <dep:hidden-classes>
            <dep:filter>org.apache.commons.io</dep:filter>
            <dep:filter>org.apache.commons.fileupload</dep:filter>
        </dep:hidden-classes>
        <dep:inverse-classloading/>        


    </dep:environment>
    <web:context-root>/DataStar</web:context-root>
</web:web-app>

6
2017-09-10 15:15



Aquí hay un ejemplo usando apache commons-fileupload:

// apache commons-fileupload to handle file upload
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(DataSources.TORRENTS_DIR()));
ServletFileUpload fileUpload = new ServletFileUpload(factory);

List<FileItem> items = fileUpload.parseRequest(req.raw());
FileItem item = items.stream()
  .filter(e ->
  "the_upload_name".equals(e.getFieldName()))
  .findFirst().get();
String fileName = item.getName();

item.write(new File(dir, fileName));
log.info(fileName);

0
2018-05-21 16:49



puede cargar archivos usando jsp / servlet.

<form action="UploadFileServlet" method="post">
  <input type="text" name="description" />
  <input type="file" name="file" />
  <input type="submit" />
</form>

por otro lado del servidor. usa el siguiente código

     package com.abc..servlet;

import java.io.File;
---------
--------


/**
 * Servlet implementation class UploadFileServlet
 */
public class UploadFileServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public UploadFileServlet() {
        super();
        // TODO Auto-generated constructor stub
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.sendRedirect("../jsp/ErrorPage.jsp");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub

            PrintWriter out = response.getWriter();
            HttpSession httpSession = request.getSession();
            String filePathUpload = (String) httpSession.getAttribute("path")!=null ? httpSession.getAttribute("path").toString() : "" ;

            String path1 =  filePathUpload;
            String filename = null;
            File path = null;
            FileItem item=null;


            boolean isMultipart = ServletFileUpload.isMultipartContent(request);

            if (isMultipart) {
                FileItemFactory factory = new DiskFileItemFactory();
                ServletFileUpload upload = new ServletFileUpload(factory);
                String FieldName = "";
                try {
                    List items = upload.parseRequest(request);
                    Iterator iterator = items.iterator();
                    while (iterator.hasNext()) {
                         item = (FileItem) iterator.next();

                            if (fieldname.equals("description")) {
                                description = item.getString();
                            }
                        }
                        if (!item.isFormField()) {
                            filename = item.getName();
                            path = new File(path1 + File.separator);
                            if (!path.exists()) {
                                boolean status = path.mkdirs();
                            }
                            /* START OF CODE FRO PRIVILEDGE*/

                            File uploadedFile = new File(path + Filename);  // for copy file
                            item.write(uploadedFile);
                            }
                        } else {
                            f1 = item.getName();
                        }

                    } // END OF WHILE 
                    response.sendRedirect("welcome.jsp");
                } catch (FileUploadException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                } 
            }   
    }

}

-1
2018-02-04 10:00