Carga de archivos JSF 2.0
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?
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.xml
cumplir 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.xml
cumplir 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
/lib
carpeta y copie todos*.jar
los archivos en su archivo/WEB-INF/lib
.Son 18 archivos, de los cuales
batik*.jar
sonxml*.jar
innecesarios para utilizar solo elt:inputFileUpload
componente. Podrías dejarlos de lado.Configure el filtro de extensiones Tomahawk en formato
web.xml
. Es el responsable de manejarmultipart/form-data
las 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 loFacesServlet
que ha definido enweb.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, FacesServlet
ya hace todo el trabajo.
¿Necesito un servlet para hacer esto?
En un entorno JSF, FacesServlet
es 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.xml
declarado como Servlet 3.0, entonces definitivamente está utilizando Servlet 3.0. Servlet 3.0 es parte de Java EE 6.
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
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.
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 MultipartMap
de otra publicación de blog .
Lo logré modificando un decode
método FileRenderer
así:
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 UploadedFile
es un POJO serializable simple que se utiliza para devolver resultados al bean de respaldo.