Luego de mucho batallar ya encontramos la contestación de esta escollo que tantos lectores de este espacio han presentado. Si deseas compartir algún detalle no dejes de aportar tu conocimiento.
Solución:
Como Kai señaló con razón en su respuesta a la pregunta actual, el problema es causado por la NativeFileUploadDecoder
como lo usa FileUploadRenderer
sin comprobar si la solicitud es una multipart/form-data
solicitud o no. Esto causará problemas cuando el componente esté presente en un formulario en el que se envía una solicitud ajax “normal”. los CommonsFileUploadDecoder
lo comprueba correctamente y es por eso que funciona correctamente en JSF 2.1, que aún no tenía un analizador de carga de archivos nativo.
Su solución de solucionar esto con un renderizador personalizado está en la dirección correcta, sin embargo, el enfoque es bastante torpe. En este caso particular, no hay absolutamente ninguna necesidad de copiar toda la clase que consta de más de 200 líneas solo para agregar algunas líneas más. En su lugar, simplemente extienda exactamente esa clase y anule exactamente el método con una verificación if antes de delegar al super de la siguiente manera:
package com.example;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.primefaces.component.fileupload.FileUploadRenderer;
public class MyFileUploadRenderer extends FileUploadRenderer
@Override
public void decode(FacesContext context, UIComponent component)
if (context.getExternalContext().getRequestContentType().toLowerCase().startsWith("multipart/"))
super.decode(context, component);
Eso es todo (mantén eso
entrada en faces-config.xml
aunque). No tiene sentido continuar la decodificación si la solicitud no es una multipart
solicitud. Las partes del archivo no estarían disponibles de todos modos (y tampoco tiene sentido volver a javax.servlet.*
API cuando la misma funcionalidad está disponible a través de ExternalContext
).
Tuve el mismo problema. Parece estar más relacionado con el
que la
componente, ya que trabaja con un
(incluso con ajax).
Tu podrías intentar:
No puedo decirte por qué o cómo funciona, pero me solucionó el problema. La desventaja, por supuesto, es que tienes que hacer el estilo tú mismo, al menos hasta que los chicos de Primefaces solucionen este problema.
EDITAR:
Después de buscar en las fuentes y depurar un poco, si descubrí que en realidad hay dos solicitudes realizadas (probé
). El primero es el multipart/form-data
uno que realmente carga el archivo. Dispara el fileUploadEvent en el Bean. Yo los magos Siguiente se presiona el botón otra forma con enctype application/www-urlencoded
se envía. Esto provoca la excepción. La conclusión es que, a diferencia de lo que escribí en el comentario, suprimir la excepción es una solución válida. Esto incluso se puede hacer de una manera que no incluya cambiar Primefaces.jar, lo cual es útil si los chicos solucionan el problema en una versión futura.
Entonces, esto es lo que se debe hacer:
- Crea una nueva clase
com.yourpackage.fileupload.FileUploadRenderer
-
Copie y pegue el siguiente código dentro de su nueva clase:
package com.yourpackage.fileupload.fileupload; import java.io.IOException; import javax.faces.FacesException; import javax.faces.component.UIComponent; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.servlet.http.HttpServletRequest; import org.primefaces.component.fileupload.CommonsFileUploadDecoder; import org.primefaces.component.fileupload.FileUpload; import org.primefaces.component.fileupload.NativeFileUploadDecoder; import org.primefaces.config.ConfigContainer; import org.primefaces.context.RequestContext; import org.primefaces.expression.SearchExpressionFacade; import org.primefaces.renderkit.CoreRenderer; import org.primefaces.util.HTML; import org.primefaces.util.WidgetBuilder; public class FileUploadRenderer extends CoreRenderer @Override public void decode(FacesContext context, UIComponent component) FileUpload fileUpload = (FileUpload) component; if (!fileUpload.isDisabled()) ConfigContainer cc = RequestContext.getCurrentInstance().getApplicationContext().getConfig(); String uploader = cc.getUploader(); boolean isAtLeastJSF22 = cc.isAtLeastJSF22(); if (uploader.equals("auto")) if (isAtLeastJSF22) if (isMultiPartRequest(context)) NativeFileUploadDecoder.decode(context, fileUpload); else CommonsFileUploadDecoder.decode(context, fileUpload); else if (uploader.equals("native")) if (!isAtLeastJSF22) throw new FacesException("native uploader requires at least a JSF 2.2 runtime"); NativeFileUploadDecoder.decode(context, fileUpload); else if (uploader.equals("commons")) CommonsFileUploadDecoder.decode(context, fileUpload); @Override public void encodeEnd(FacesContext context, UIComponent component) throws IOException FileUpload fileUpload = (FileUpload) component; encodeMarkup(context, fileUpload); if (fileUpload.getMode().equals("advanced")) encodeScript(context, fileUpload); protected void encodeScript(FacesContext context, FileUpload fileUpload) throws IOException String clientId = fileUpload.getClientId(context); String update = fileUpload.getUpdate(); String process = fileUpload.getProcess(); WidgetBuilder wb = getWidgetBuilder(context); wb.initWithDomReady("FileUpload", fileUpload.resolveWidgetVar(), clientId, "fileupload"); wb.attr("auto", fileUpload.isAuto(), false) .attr("dnd", fileUpload.isDragDropSupport(), true) .attr("update", SearchExpressionFacade.resolveComponentsForClient(context, fileUpload, update), null) .attr("process", SearchExpressionFacade.resolveComponentsForClient(context, fileUpload, process), null) .attr("maxFileSize", fileUpload.getSizeLimit(), Long.MAX_VALUE) .attr("fileLimit", fileUpload.getFileLimit(), Integer.MAX_VALUE) .attr("invalidFileMessage", fileUpload.getInvalidFileMessage(), null) .attr("invalidSizeMessage", fileUpload.getInvalidSizeMessage(), null) .attr("fileLimitMessage", fileUpload.getFileLimitMessage(), null) .attr("messageTemplate", fileUpload.getMessageTemplate(), null) .attr("previewWidth", fileUpload.getPreviewWidth(), 80) .attr("disabled", fileUpload.isDisabled(), false) .callback("onstart", "function()", fileUpload.getOnstart()) .callback("onerror", "function()", fileUpload.getOnerror()) .callback("oncomplete", "function()", fileUpload.getOncomplete()); if (fileUpload.getAllowTypes() != null) wb.append(",allowTypes:").append(fileUpload.getAllowTypes()); wb.finish(); protected void encodeMarkup(FacesContext context, FileUpload fileUpload) throws IOException if (fileUpload.getMode().equals("simple")) encodeSimpleMarkup(context, fileUpload); else encodeAdvancedMarkup(context, fileUpload); protected void encodeAdvancedMarkup(FacesContext context, FileUpload fileUpload) throws IOException ResponseWriter writer = context.getResponseWriter(); String clientId = fileUpload.getClientId(context); String style = fileUpload.getStyle(); String styleClass = fileUpload.getStyleClass(); styleClass = styleClass == null ? FileUpload.CONTAINER_CLASS : FileUpload.CONTAINER_CLASS + " " + styleClass; boolean disabled = fileUpload.isDisabled(); writer.startElement("div", fileUpload); writer.writeAttribute("id", clientId, "id"); writer.writeAttribute("class", styleClass, styleClass); if (style != null) writer.writeAttribute("style", style, "style"); //buttonbar writer.startElement("div", fileUpload); writer.writeAttribute("class", FileUpload.BUTTON_BAR_CLASS, null); //choose button encodeChooseButton(context, fileUpload, disabled); if (!fileUpload.isAuto()) encodeButton(context, fileUpload.getUploadLabel(), FileUpload.UPLOAD_BUTTON_CLASS, "ui-icon-arrowreturnthick-1-n"); encodeButton(context, fileUpload.getCancelLabel(), FileUpload.CANCEL_BUTTON_CLASS, "ui-icon-cancel"); writer.endElement("div"); //content writer.startElement("div", null); writer.writeAttribute("class", FileUpload.CONTENT_CLASS, null); writer.startElement("table", null); writer.writeAttribute("class", FileUpload.FILES_CLASS, null); writer.startElement("tbody", null); writer.endElement("tbody"); writer.endElement("table"); writer.endElement("div"); writer.endElement("div"); protected void encodeSimpleMarkup(FacesContext context, FileUpload fileUpload) throws IOException encodeInputField(context, fileUpload, fileUpload.getClientId(context)); protected void encodeChooseButton(FacesContext context, FileUpload fileUpload, boolean disabled) throws IOException ResponseWriter writer = context.getResponseWriter(); String clientId = fileUpload.getClientId(context); String cssClass = HTML.BUTTON_TEXT_ICON_LEFT_BUTTON_CLASS + " " + FileUpload.CHOOSE_BUTTON_CLASS; if (disabled) cssClass += " ui-state-disabled"; writer.startElement("span", null); writer.writeAttribute("class", cssClass, null); //button icon writer.startElement("span", null); writer.writeAttribute("class", HTML.BUTTON_LEFT_ICON_CLASS + " ui-icon-plusthick", null); writer.endElement("span"); //text writer.startElement("span", null); writer.writeAttribute("class", HTML.BUTTON_TEXT_CLASS, null); writer.writeText(fileUpload.getLabel(), "value"); writer.endElement("span"); if (!disabled) encodeInputField(context, fileUpload, clientId + "_input"); writer.endElement("span"); protected void encodeInputField(FacesContext context, FileUpload fileUpload, String clientId) throws IOException ResponseWriter writer = context.getResponseWriter(); writer.startElement("input", null); writer.writeAttribute("type", "file", null); writer.writeAttribute("id", clientId, null); writer.writeAttribute("name", clientId, null); if (fileUpload.isMultiple()) writer.writeAttribute("multiple", "multiple", null); if (fileUpload.getStyle() != null) writer.writeAttribute("style", fileUpload.getStyle(), "style"); if (fileUpload.getStyleClass() != null) writer.writeAttribute("class", fileUpload.getStyleClass(), "styleClass"); if (fileUpload.isDisabled()) writer.writeAttribute("disabled", "disabled", "disabled"); writer.endElement("input"); protected void encodeButton(FacesContext context, String label, String styleClass, String icon) throws IOException ResponseWriter writer = context.getResponseWriter(); String cssClass = HTML.BUTTON_TEXT_ICON_LEFT_BUTTON_CLASS + " ui-state-disabled " + styleClass; writer.startElement("button", null); writer.writeAttribute("type", "button", null); writer.writeAttribute("class", cssClass, null); writer.writeAttribute("disabled", "disabled", null); //button icon String iconClass = HTML.BUTTON_LEFT_ICON_CLASS; writer.startElement("span", null); writer.writeAttribute("class", iconClass + " " + icon, null); writer.endElement("span"); //text writer.startElement("span", null); writer.writeAttribute("class", HTML.BUTTON_TEXT_CLASS, null); writer.writeText(label, "value"); writer.endElement("span"); writer.endElement("button"); private boolean isMultiPartRequest(FacesContext context) if (context == null) return false; return ((HttpServletRequest) context.getExternalContext().getRequest()).getContentType().startsWith("multipart");
-
Agregue las siguientes líneas en la parte inferior de su
faces-config.xml
:org.primefaces.component org.primefaces.component.FileUploadRenderer com.yourpackage.fileupload.FileUploadRenderer -
Usted está listo para ir!
¿Qué hemos hecho? Creamos nuestro propio FileUploadRenderer que comprueba si el contentType es realmente multipart/form-data
usando el método isMultiPartRequest()
. Solo si esto vuelve true se ejecuta el resto del código. En cualquier otro caso, no sucederá nada, lo que significa que no se lanzará ninguna excepción. Si Primefaces soluciona este problema, solo necesita eliminar las líneas de su faces-config.xml
para usar su clase.
¡Avísame si eso funciona para ti!
EDITAR
Este código verifica si la solicitud dada es de tipo multipart / form-data. Si no es así, se detiene la ejecución. El código original de Primefaces continuaría de todos modos. Como mencioné anteriormente, si carga un archivo dentro de un componente Primefaces, en realidad se realizan dos solicitudes:
- El Ajax-FileUpload usando el
(enctype:multipart/form-data
) - La acción del Ajax en el
o
(enctype:application/www-form-urlencoded
)
El primero es manejado por el renderizador mientras que el segundo causa la excepción en el código original ya que el renderizador intenta manejar algo de lo que no es capaz. Solo con los cambios realizados en el código multipart/form-data
Los formularios son manejados por el renderizador por lo que no ocurren excepciones. En mi opinión, es claramente un error en las fuentes de Primefaces. Las diferencias de código son solo el método private boolean isMultiPartRequest(FacesContext context)
y su única aparición en el código. ¡Me alegro de poder ayudarte!
Aunque esto es antiguo y ya está respondido, quería compartir algo, en caso de que se lo perdiera: PrimeFaces 4+ ahora tiene un parámetro de contexto, que puede usar (en web.xml) para elegir manualmente qué cargador debe usarse (nativo -servlet3 o commons). Puede usar esto para forzar el cargador común de esta manera:
primefaces.UPLOADER
commons
(Por supuesto, todavía necesita FileUploadFilter como se describe arriba y en la guía). Consulte la Guía del usuario de PrimeFaces para obtener más información.