Fileupload y JSF 2.0

En esta cuarta entrega abordaremos la subida de archivos con JSF, como paso previo al almacenamiento en base de datos con JPA, que abordemos en una futura entrega.
Para esto necesitamos tener soporte para los formularios ' form enctype="multipart/form-data" ' que nos permiten enviar archivos al servidor. Para ello necesitamos dos cosas, un flitro en el servlet que nos gestione ese envio y un contenedor. El componente va a ser "tomahawk" y el contenedor  un UploadedFile del mismo proyecto.
Para tenerlos disponible tenemos que añadirlo a nuestro proyecto maven con dos dependencias, la segúnda unicamente nos proporciona unas cuantas utilidades altamente recomendables para el tratamiento de archivos.
         <dependency>
            <groupId>org.apache.myfaces.tomahawk</groupId>
            <artifactId>tomahawk12</artifactId>
            <version>1.1.9</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.0.1</version>
        </dependency>

Ahora vamos a configurar el servlet para que se capturen apropiadamente los envios. En el web.xml debemos configurar:

    <!-- Faces Servlet -->
    <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>/faces/*</url-pattern>
    </servlet-mapping>

    <!-- Filtro encargardo de gestionar los archivos multipart/formdata -->
    <filter>
        <filter-name>SubidorArchivos</filter-name>
        <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
    </filter>
   
    <filter-mapping>
        <filter-name>SubidorArchivos</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>

La primera parte es la que ya conocíamos, la segunda define el filter y lo asocia al "Faces Servlet".

Queda por escribir la página que sube los archivos, pero vayamos antes a la clase que va gestionar el archivo y que contiene el contenedor: UploadBean.java:

package es.sinjava;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Logger;
import org.apache.myfaces.custom.fileupload.UploadedFile;

@ManagedBean
@RequestScoped
public class UploadBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private final Logger log = Logger.getLogger(UploadBean.class);

    private UploadedFile uploadedFile;

    public String upToServer(){
        log.trace("Begin upToServer");
         String fileName = FilenameUtils.getName(uploadedFile.getName());
         String contentType = uploadedFile.getContentType();
            log.debug("Subido el archivo : " + fileName + "/n De tipo : "+ contentType );
        return "succesUpload";
    }

    public UploadedFile getUploadedFile() {
        return uploadedFile;
    }

    public void setUploadedFile(UploadedFile uploadedFile) {
        this.uploadedFile = uploadedFile;
    }
}

Cuando se ejecute el "upToServer" en el "UploadedFile" definido tendremos el archivoy de momento no haremos otra manipulación que extraer el nombre del archivo con la clase de utilidad FilenameUtils y el tamaño del archivo.Si alguien no tiene la suficiente fe y duda que el archivo esté en el contenedor, puede hacer alguna manipulación más laboriosa como volcar el UploadedFile en un archivo.

Algo del tipo:
            OutputStream fw= new FileOutputStream("C:\\"+ fileName);
            byte[] b = new byte[1024];
            while (uploadedFile.getInputStream().read(b)>0){
                fw.write(b);
            }
            fw.close();


La salida, successUpload.xhtml, lo declaro así, omito las parte comunes a cualquier página, que al estar trabajando con plantillas es el 80%.:
...
        <ui:define name="content">
            <h:outputFormat value="#{msg.successUpload}">
                <f:param value="#{user.name}" />
                <f:param value="#{uploadBean.uploadedFile.name}" />
                <f:param value="#{uploadBean.uploadedFile.contentType}" />   
            </h:outputFormat>           
        </ui:define>
 ...

En los literales properties he definido el literal successUpload como "Enhorabuena  {0},  has subido el archivo {1} de tipo {2} "

Hecho todo esto debería desplegar y compilar. En cualquier caso dejo el proyecto aquí completo.








Comentarios