Carga de archivos JSF 2.0

Resuelto javing asked hace 13 años • 8 respuestas

Estoy buscando en algunos blogs para intentar encontrar cómo cargar archivos usando JSF 2.0, pero todas las soluciones me confunden. Me gustaría saber qué necesito exactamente para poder cargar correctamente un archivo (MP3, PDF, vídeo... cualquier tipo) y almacenarlo en una base de datos como @Lob. Esto es lo que he hecho hasta ahora:

  • Creé una entidad que tiene un atributo de tipo byte[] y también está anotada con una anotación @Lob.

  • Creé un EJB que introducirá la entidad con un método que tiene un byte [] como parámetro y lo insertará en la base de datos usando la clase EntityManager (método persistente).

  • Creé una página JSF con una etiqueta de entrada de tipo "archivo" y un botón de enviar

  • Preparé un bean administrado para intercambiar información sobre el archivo con la página JSF.

Ahora estoy estancado y tengo muchas dudas:

  • ¿Qué debo hacer para pasar el archivo del JSF al bean administrado y luego transformarlo en un byte [] (para poder manejarlo en el EJB)?

  • ¿Cómo puede ayudarme un servlet?

  • ¿Necesito un servlet para hacer esto?

  • También encontré que en algún blog menciona algo sobre servlets 3.0, pero no sé si mi entorno de trabajo lo está usando, ¿cómo puedo hacerlo si estoy usando servlets 3.0 (estoy usando JEE6)?

Nunca antes había subido archivos y tampoco estoy muy familiarizado con los servlets. Estoy confundido, ¿alguien podría darme algunos consejos iniciales, por favor?

javing avatar Mar 24 '11 18:03 javing
Aceptado

En primer lugar, esta (antigua) pregunta y respuesta supone JSF 2.0/2.1. Desde JSF 2.2 hay un <h:inputFile>componente nativo sin necesidad de bibliotecas de componentes de terceros. Consulte también ¿Cómo cargar un archivo usando JSF 2.2 <h:inputFile>? ¿Dónde está el archivo guardado?


La forma más sencilla sería utilizar Tomahawk para JSF 2.0 . Ofrece un <t:inputFileUpload>componente.

Aquí tienes un tutorial paso a paso:

  • Cree un proyecto web dinámico en blanco para Servlet 3.0 y JSF 2.0. Debe web.xmlcumplir con las especificaciones de Servlet 3.0 y ya contener el servlet JSF:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        id="YourProjectName" version="3.0">
    
        <display-name>Your Project Name</display-name>
    
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>*.xhtml</url-pattern>
        </servlet-mapping>
    
    </web-app>
    

    Debe faces-config.xmlcumplir con la especificación JSF 2.0:

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
        version="2.0">
    
    </faces-config>
    

  • Descargue Tomahawk 1.1.10 para JSF 2.0 . Extraiga el archivo zip, vaya a la /libcarpeta y copie todos *.jarlos archivos en su archivo /WEB-INF/lib.

    Son 18 archivos, de los cuales batik*.jarson xml*.jarinnecesarios para utilizar solo el t:inputFileUploadcomponente. Podrías dejarlos de lado.


  • Configure el filtro de extensiones Tomahawk en formato web.xml. Es el responsable de manejar multipart/form-datalas solicitudes necesarias para poder enviar archivos a través de HTTP.

    <filter>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>
    

    Tenga en cuenta que <servlet-name>debe coincidir exactamente <servlet-name>con lo FacesServletque ha definido en web.xml.


  • Crea una faceta simple upload.xhtml:

    <!DOCTYPE html>
    <html lang="en"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:t="http://myfaces.apache.org/tomahawk"
        xmlns:ui="http://java.sun.com/jsf/facelets">
        <h:head>
            <title>Tomahawk file upload demo</title>
        </h:head>
        <h:body>
            <h:form enctype="multipart/form-data">
                <t:inputFileUpload value="#{bean.uploadedFile}" />
                <h:commandButton value="submit" action="#{bean.submit}" />
                <h:messages />
            </h:form>
        </h:body> 
    </html>
    

    Tenga en cuenta el enctype="multipart/form-data"atributo en <h:form>, esto es muy importante para poder enviar archivos con HTTP.


  • Cree un bean administrado simple com.example.Bean:

    package com.example;
    
    import java.io.IOException;
    
    import javax.faces.application.FacesMessage;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.RequestScoped;
    import javax.faces.context.FacesContext;
    
    import org.apache.commons.io.FilenameUtils;
    import org.apache.myfaces.custom.fileupload.UploadedFile;
    
    @ManagedBean
    @RequestScoped
    public class Bean {
    
        private UploadedFile uploadedFile;
    
        public void submit() throws IOException {
            String fileName = FilenameUtils.getName(uploadedFile.getName());
            String contentType = uploadedFile.getContentType();
            byte[] bytes = uploadedFile.getBytes();
    
            // Now you can save bytes in DB (and also content type?)
    
            FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage(String.format("File '%s' of type '%s' successfully uploaded!", fileName, contentType)));
        }
    
        public UploadedFile getUploadedFile() {
            return uploadedFile;
        }
    
        public void setUploadedFile(UploadedFile uploadedFile) {
            this.uploadedFile = uploadedFile;
        }
    
    }
    

Eso debería ser todo. Ábralo mediante http://localhost:8080/projectname/upload.xhtml .

En cuanto a sus preguntas concretas:

¿Qué debo hacer para pasar el archivo del JSF al bean administrado y luego transformarlo en un byte [] (para poder manejarlo en el EJB)?

Esto se responde arriba.

¿Cómo puede ayudarme un servlet?

Es capaz de procesar y controlar solicitudes/respuestas HTTP. En un entorno JSF, FacesServletya hace todo el trabajo.

¿Necesito un servlet para hacer esto?

En un entorno JSF, FacesServletes obligatorio. Pero ya lo proporciona la API, no es necesario que escriba uno usted mismo. Sin embargo, para poder descargar archivos de una base de datos, definitivamente es útil otro servlet. Puede encontrar un ejemplo básico aquí: Servlet para servir contenido estático .

También descubrí que en algún blog se menciona algo sobre los servlets 3.0, pero no sé si mi entorno de trabajo los está usando, ¿cómo puedo hacerlo si estoy usando servlets 3.0 (estoy usando JEE6)?

Si está utilizando un contenedor Servlet 3.0 como Glassfish 3, JBoss AS 6, Tomcat 7, etc. y está web.xmldeclarado como Servlet 3.0, entonces definitivamente está utilizando Servlet 3.0. Servlet 3.0 es parte de Java EE 6.

BalusC avatar Mar 24 '2011 19:03 BalusC

Para completar, solo quiero proporcionar un ejemplo independiente y completamente funcional de cómo se hace esto con JSF 2.2, ya sea con solicitudes Ajax y no Ajax . Tenga en cuenta que JSF 2.2 usa diferentes espacios de nombres y debe trabajar con un contenedor Servlet 3.0 (como lo son Tomcat 7.0.x, JBoss AS 6.x y 7.x y GlassFish 3.x).

archivoSubir.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head />
<h:body>
    <h:form enctype="multipart/form-data">
        <h:inputFile value="#{uploadBean.file}" />
        <h:commandButton value="Post Upload" action="#{uploadBean.upload}" />
    </h:form>
    <h:form enctype="multipart/form-data">
        <h:inputFile value="#{uploadBean.file}" />
        <h:commandButton value="Ajax Upload">
            <f:ajax listener="#{uploadBean.upload}" execute="@form"
                render="countOutput" />
        </h:commandButton>
    <!-- Counts the uploaded items -->
    <h:outputText id="countOutput"
        value="Files uploaded #{uploadBean.filesUploaded}" />
    </h:form>
</h:body>
</html>

SubirBean.java:

@ManagedBean
@ViewScoped
public class UploadBean {

    private int filesUploaded = 0;

    //javax.servlet.http.Part (Servlet 3.0 API)
    private Part file;
    private String fileContent;

    /**
     * Just prints out file content
     */
    public void upload() {
        try {
            fileContent = new Scanner(file.getInputStream())
                    .useDelimiter("\\A").next();
            System.out.println(fileContent + " uploaded");
            filesUploaded++;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public int getFilesUploaded() {
        return filesUploaded;
    }

    public Part getFile() {
        return file;
    }

    public void setFile(Part file) {
        this.file = file;
    }
}

Ver también:

  • JSF 2.2: carga de archivos con h:inputFile
Aritz avatar Feb 06 '2014 08:02 Aritz

Recomendaría utilizar una biblioteca de componentes como Tomahawk's<t:inputFileUpload> o PrimeFaces<p:fileUpload> .

BalusC también tiene una buena publicación en el blog sobre la carga de archivos con JSF 2.0 y Servlet 3.0.

Mark avatar Mar 24 '2011 18:03 Mark

Publicación del blog de BalusC: Cargar archivos con JSF 2.0 y Servlet 3.0 es lo que me salvó, porque tuve problemas al ejecutar la etiqueta fileUpload de RichFaces 4 con Spring WebFlow.

Vale la pena modificar el código de BalusC para usar el de Spring MultipartResolver; no necesitas el MultipartMapde otra publicación de blog .

Lo logré modificando un decodemétodo FileRendererasí:

    UploadedFile ret = null;

    Object req = context.getExternalContext().getRequest();
    if (req instanceof MultipartHttpServletRequest) {
      MultipartFile file = ((MultipartHttpServletRequest)req).getFile(clientId);

      File temp = null;
      try {
        temp = File.createTempFile("_UPLOAD_", null);
        file.transferTo(temp);

        String name = new File(file.getOriginalFilename()).getName();
        ret = new UploadedFile(temp, name);

      } catch (IOException e) {
        throw new RuntimeException("Could not create temp file.", e);
      }
    } else {
      throw new IllegalStateException("Request is not multipart. Use spring's multipart resolver.");
    }
    // If no file is specified, set empty String to trigger validators.
    ((UIInput) component).setSubmittedValue( ret == null ? EMPTY_STRING : ret);

A UploadedFilees un POJO serializable simple que se utiliza para devolver resultados al bean de respaldo.

Maciej Łoziński avatar Jan 08 '2013 14:01 Maciej Łoziński