Cómo usar PrimeFaces p: fileUpload? El método Listener nunca se invoca o UploadedFile es nulo / arroja un error / no se puede usar

fileUploadListener subir un archivo usando PrimeFaces, pero el método fileUploadListener no se invoca una vez que finaliza la carga.

Aquí está la vista:

  

Y el frijol:

 @ManagedBean @RequestScoped public class FileUploadController { public void handleFileUpload(FileUploadEvent event) { FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded."); FacesContext.getCurrentInstance().addMessage(null, msg); } } 

He colocado un punto de interrupción en el método, pero nunca se llama. Cuando se usa mode="simple" y ajax="false" , se invoca, pero quiero que funcione en el modo avanzado. Estoy usando Netbeans y Glassfish 3.1.

Cómo configurar y solucionar problemas depende de la versión de PrimeFaces.

Todas las versiones de PrimeFaces

Los siguientes requisitos se aplican a todas las versiones de PrimeFaces:

  1. El atributo enctype de debe establecerse en multipart/form-data . Cuando esto está ausente, la carga de Ajax puede funcionar, pero el comportamiento general del navegador no está especificado y depende de la composición de la forma y la versión / versión del navegador web. Simplemente siempre especifique que esté en el lado seguro.

  2. Cuando se utiliza mode="advanced" (es decir, ajax upload, este es el valor predeterminado), entonces asegúrese de tener un en la plantilla (principal). Esto asegurará que los archivos necesarios de JavaScript estén incluidos correctamente. Esto no es necesario para mode="simple" (subida no ajax), pero esto rompería la apariencia y la funcionalidad de todos los demás componentes de PrimeFaces, por lo que no querrá perderse eso de todos modos.

  3. Cuando se utiliza mode="simple" (es decir, carga no ajax), ajax debe estar deshabilitado en cualquier botón / enlace de comandos PrimeFaces por ajax="false" , y debe usar con lugar de .

Por lo tanto, si desea subir archivos (automático) con soporte para javascript (tenga en cuenta la !):

    
 public void upload(FileUploadEvent event) { UploadedFile uploadedFile = event.getFile(); String fileName = uploadedFile.getFileName(); String contentType = uploadedFile.getContentType(); byte[] contents = uploadedFile.getContents(); // Or getInputStream() // ... Save it, now! } 

O si desea cargar un archivo que no sea ajax:

     
 private UploadedFile uploadedFile; // +getter+setter public void upload() { String fileName = uploadedFile.getFileName(); String contentType = uploadedFile.getContentType(); byte[] contents = uploadedFile.getContents(); // Or getInputStream() // ... Save it, now! } 

Tenga en cuenta que los atributos relacionados con ajax como auto , allowTypes , update , onstart , oncomplete , etc. se ignoran en mode="simple" . Por lo tanto, es innecesario especificarlos en tal caso.

También tenga en cuenta que debe leer el contenido del archivo inmediatamente dentro de los métodos mencionados anteriormente y no en un método de bean diferente invocado por una solicitud HTTP posterior. Esto se debe a que el contenido del archivo subido tiene un ámbito de solicitud y, por lo tanto, no está disponible en una solicitud HTTP posterior / diferente. Cualquier bash de leerlo en una solicitud posterior muy probablemente terminará con java.io.FileNotFoundException en el archivo temporal.


PrimeFaces 5.x

Esto no requiere ninguna configuración adicional si está utilizando JSF 2.2 y su faces-config.xml también se declara conforme a la versión JSF 2.2. No necesita el filtro de carga del archivo PrimeFaces. En caso de que no esté claro cómo instalar y configurar correctamente JSF según el servidor de destino utilizado, diríjase a ¿Cómo instalar y configurar correctamente las bibliotecas JSF a través de Maven? y la sección “Instalando JSF” de nuestra página wiki de JSF .

Sin embargo, si todavía no está utilizando JSF 2.2 y no puede actualizarlo (debería ser fácil cuando ya está en un contenedor compatible con Servlet 3.0), entonces necesita registrar manualmente el filtro de carga de archivo PrimeFaces en web.xml (lo hará analizar la solicitud de varias partes y completar el mapa de parámetros de solicitud habitual para que FacesServlet pueda continuar funcionando como siempre):

  primeFacesFileUploadFilter org.primefaces.webapp.filter.FileUploadFilter   primeFacesFileUploadFilter facesServlet  

El valor de de facesServlet debe coincidir exactamente con el valor de la entrada de javax.faces.webapp.FacesServlet en el mismo web.xml . Entonces, si es, por ejemplo, Faces Servlet , entonces debe editarlo para que coincida.


PrimeFaces 4.x

La misma historia que PrimeFaces 5.x se aplica en 4.x también.

Solo hay un problema potencial para que UploadedFile#getContents() contenido del archivo cargado. Esto devolverá null cuando se use API nativa en lugar de Apache Commons FileUpload. Necesita usar UploadedFile#getInputStream() lugar. Consulte también Cómo insertar imágenes cargadas de p: fileUpload como BLOB en MySQL?

Otro problema potencial con la API nativa se manifestará cuando el componente de carga esté presente en un formulario en el que se activa una solicitud ajax “regular” diferente que no procesa el componente de carga. Consulte también La carga de archivos no funciona con AJAX en PrimeFaces 4.0 / JSF 2.2.x – javax.servlet.ServletException: el tipo de contenido de solicitud no es un multipart / form-data .

Ambos problemas también se pueden resolver cambiando a Apache Commons FileUpload. Vea la sección de PrimeFaces 3.x para más detalles.


PrimeFaces 3.x

Esta versión no es compatible con la carga de archivos nativos de JSF 2.2 / Servlet 3.0. Debe instalar Apache Commons FileUpload manualmente y registrar explícitamente el filtro de carga de archivos en web.xml .

Necesitas las siguientes bibliotecas:

  • commons-fileupload.jar
  • commons-io.jar

Esos deben estar presentes en el classpath del tiempo de ejecución de webapp. Cuando use Maven, asegúrese de que al menos tengan un scope de tiempo de ejecución (el scope predeterminado de la comstackción también es bueno). Al transportar manualmente los JAR, asegúrese de que terminan en la carpeta /WEB-INF/lib .

El detalle de registro del filtro de carga de archivos se puede encontrar en la sección PrimeFaces 5.x aquí arriba. En caso de que esté utilizando PrimeFaces 4+ y desee utilizar explícitamente Apache Commons FileUpload en lugar de la carga de archivos nativos JSF 2.2 / Servlet 3.0, entonces necesita junto a las bibliotecas mencionadas y filtrar también el param siguiente del contexto en web.xml :

  primefaces.UPLOADER commons  

Solución de problemas

En caso de que todavía no funcione, aquí hay otras causas posibles que no están relacionadas con la configuración de PrimeFaces:

  1. Solo si está utilizando el filtro de carga de archivo PrimeFaces: hay otro Filter en su aplicación web que se ejecuta antes del filtro de carga de archivo PrimeFaces y ya ha consumido el cuerpo de la solicitud, por ejemplo llamando getParameter() , getParameterMap() , getReader() , etcétera. Un cuerpo de solicitud puede analizarse solo una vez. Cuando llama a uno de esos métodos antes de que el filtro de carga de archivos haga su trabajo, el filtro de carga de archivos obtendrá un cuerpo de solicitud vacío.

    Para solucionar esto, debe colocar del filtro de carga de archivo antes que el otro filtro en web.xml . Si la solicitud no es una solicitud multipart/form-data , entonces el filtro de carga de archivo continuará como si nada hubiera sucedido. Si utiliza filtros que se agregan automágicamente porque usan anotaciones (por ejemplo, PrettyFaces), es posible que necesite agregar pedidos explícitos a través de web.xml. Consulte Cómo definir el orden de ejecución del filtro de servlet utilizando anotaciones en WAR

  2. Solo si está utilizando el filtro de carga de archivo PrimeFaces: hay otro Filter en su aplicación web que se ejecuta antes del filtro de carga de archivo PrimeFaces y ha realizado una llamada a RequestDispatcher#forward() . Por lo general, los filtros de reescritura de URL como PrettyFaces hacen esto. Esto desencadena el despachador FORWARD , pero los filtros se escuchan de forma predeterminada solo en el despachador REQUEST .

    Para solucionarlo, necesitaría colocar el filtro de carga del archivo PrimeFaces antes del filtro de reenvío, o volver a configurar el filtro de carga del archivo PrimeFaces para escuchar también en el despachador FORWARD :

      primeFacesFileUploadFilter facesServlet REQUEST FORWARD  
  3. Hay una anidada. Esto es ilegal en HTML y el comportamiento del navegador no está especificado. Con más frecuencia, el navegador no enviará los datos esperados en el envío. Asegúrese de no anidar . Esto es completamente independientemente del enctype de la forma. Simplemente no anides formularios en absoluto.

Si todavía tiene problemas, bien, depure el tráfico HTTP. Abra el conjunto de herramientas del desarrollador del navegador web (presione F12 en Chrome / Firebug23 + / IE9 +) y revise la sección Red / Red. Si la parte HTTP se ve bien, entonces depure el código JSF. Coloque un punto de interrupción en FileUploadRenderer#decode() y avance desde allí.


Guardar archivo cargado

Después de que finalmente lo haya hecho funcionar, su próxima pregunta probablemente será como “¿Cómo / dónde guardo el archivo cargado?”. Bueno, continúe aquí: Cómo guardar el archivo cargado en JSF .

¿Usas también las cosas bonitas? A continuación, establezca el despachador en FORWARD:

  PrimeFaces FileUpload Filter Faces Servlet FORWARD  

Un punto que noté con Primefaces 3.4 y Netbeans 7.2:

Elimine los parámetros autocompletados de Netbeans para la función handleFileUpload ie (evento), de lo contrario el evento podría ser nulo.

     

Parece que javax.faces.SEPARATOR_CHAR no debe ser igual a _

Tuve el mismo problema con Primefaces 5.3 y pasé por todos los puntos descritos por BalusC sin ningún resultado. Seguí su consejo de depurar FileUploadRenderer # decode () y descubrí que mi web.xml estaba mal configurado

  primefaces.UPLOADER auto|native|commons  

¡El valor de param debe ser 1 de estos 3 valores, pero no todos! Toda la sección de parámetros de contexto se puede eliminar y el valor predeterminado será automático

bean.xhtml

      

Bean.java

 @ManagedBean 

@ViewScoped public class La presentación implementa Serializable {

 private UploadedFile file; //Gets //Sets public void uploadFasta(FileUploadEvent event) throws FileNotFoundException, IOException, InterruptedException { String content = IOUtils.toString(event.getFile().getInputstream(), "UTF-8"); String filePath = PATH + "resources/submissions/" + nameOfMyFile + ".pdf"; MyFileWriter.writeFile(filePath, content); FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, event.getFile().getFileName() + " is uploaded.", null); FacesContext.getCurrentInstance().addMessage(null, message); } 

}

web.xml

   Faces Servlet *.xhtml   PrimeFaces FileUpload Filter org.primefaces.webapp.filter.FileUploadFilter   PrimeFaces FileUpload Filter Faces Servlet  

Ninguna de las sugerencias aquí fue útil para mí. Así que tuve que depurar las caras y descubrí que el motivo del problema era:

 java.lang.IllegalStateException: No multipart config for servlet fileUpload 

Luego he agregado la sección en mi servlet de caras en el web.xml. Entonces eso ha solucionado el problema:

  main org.apache.myfaces.webapp.MyFacesServlet 1  /tmp 20848820 418018841 1048576   

Tuve el mismo problema, debido al hecho de que tenía toda la configuración que describo en esta publicación, pero en mi caso se debía a que tenía dos importaciones de jquery (una de ellas era la consulta de Primefaces) que causaba que los conflictos subieran archivos.

Ver Primefaces Jquery conflict