web-dev-qa-db-fra.com

Le téléchargement de fichiers ne fonctionne pas avec AJAX dans PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: le type de contenu de la demande n'est pas un multipart / form-data

Important: Le problème discuté dans ce fil a été corrigé en date du PrimeFaces 5.1 final (version communautaire) publié le lundi 6 octobre 2014 (il y a seulement quelques minutes). J'ai essayé sur JSF 2.2.8-02 (ou api , impl ).

En tant que tel, s'il vous arrivait d'utiliser cette version (ou plus, pas besoin de mentionner), vous n'auriez même plus besoin de lire cette question.


J'ai une application Web fonctionnant sur

  • GlassFish 4.0
  • Mojarra 2.2.4
  • PrimeFaces 4.0 final

Tout sauf le téléchargement de fichiers avec AJAX fonctionne bien. Le fichier xhtml suivant envoie du contenu en plusieurs parties via une demande AJAX déclenchée par un bouton de commande PrimeFaces).

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:p="http://primefaces.org/ui"
      xmlns:h="http://Java.Sun.com/jsf/html"
      xmlns:f="http://Java.Sun.com/jsf/core">
    <h:head>
        <title>Test</title>
    </h:head>
    <h:body>
        <h:form prependId="true" enctype="multipart/form-data">
            <p:fileUpload id="txtCatImage"
                          value="#{testManagedBean.uploadedFile}"
                          mode="advanced"
                          dragDropSupport="true"
                          fileLimit="1"
                          sizeLimit="100000"
                          multiple="false"
                          allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
                          fileUploadListener="#{testManagedBean.fileUploadListener}"/>

            <p:message for="txtCatImage" showSummary="false"/>
            <p:commandButton id="btnSubmit" 
                             actionListener="#{testManagedBean.insert}" 
                             ajax="true" icon="ui-icon-check" value="Save"/>                
        </h:form>
    </h:body>
</html>

Le bean géré test:

@ManagedBean
@ViewScoped
public final class TestManagedBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private UploadedFile uploadedFile;

    public TestManagedBean(){}

    public UploadedFile getUploadedFile() {
        return uploadedFile;
    }

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

    public void fileUploadListener(FileUploadEvent event){
        uploadedFile=event.getFile();
    }

    public void insert(){
        if(uploadedFile!=null){
            System.out.println(uploadedFile.getFileName());
        }
        else{
            System.out.println("The file object is null.");
        }
    }
}

Lorsqu'un fichier est téléchargé à partir d'un navigateur de fichiers, il affiche le nom du fichier dans son écouteur - fileUploadListener().

Après avoir téléchargé un fichier, lorsque le bouton de commande donné est enfoncé (ajax="true"), Il provoque la levée de l'exception suivante.

WARNING:   javax.servlet.ServletException: The request content-type is not a multipart/form-data
javax.faces.FacesException: javax.servlet.ServletException: The request content-type is not a multipart/form-data
    at org.primefaces.component.fileupload.NativeFileUploadDecoder.decode(NativeFileUploadDecoder.Java:44)
    at org.primefaces.component.fileupload.FileUploadRenderer.decode(FileUploadRenderer.Java:44)
    at javax.faces.component.UIComponentBase.decode(UIComponentBase.Java:831)
    at javax.faces.component.UIInput.decode(UIInput.Java:771)
    at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.Java:1225)
    at javax.faces.component.UIInput.processDecodes(UIInput.Java:676)
    at javax.faces.component.UIForm.processDecodes(UIForm.Java:225)
    at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.Java:1220)
    at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.Java:1220)
    at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.Java:929)
    at com.Sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.Java:78)
    at com.Sun.faces.lifecycle.Phase.doPhase(Phase.Java:101)
    at com.Sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.Java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.Java:646)
    at org.Apache.catalina.core.StandardWrapper.service(StandardWrapper.Java:1682)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:344)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:214)
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.Java:70)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:256)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:214)
    at filter.NoCacheFilter.doFilter(NoCacheFilter.Java:28)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:256)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:214)
    at org.Apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:316)
    at org.Apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java:160)
    at org.Apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.Java:734)
    at org.Apache.catalina.core.StandardPipeline.invoke(StandardPipeline.Java:673)
    at com.Sun.enterprise.web.WebPipeline.invoke(WebPipeline.Java:99)
    at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:174)
    at org.Apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.Java:357)
    at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:260)
    at com.Sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.Java:188)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.Java:191)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.Java:168)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.Java:189)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.Java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.Java:288)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.Java:206)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.Java:136)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.Java:114)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.Java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.Java:838)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.Java:113)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.Java:115)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.Java:55)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.Java:135)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.Java:564)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.Java:544)
    at Java.lang.Thread.run(Thread.Java:722)
Caused by: javax.servlet.ServletException: The request content-type is not a multipart/form-data
    at org.Apache.catalina.fileupload.Multipart.getPart(Multipart.Java:187)
    at org.Apache.catalina.connector.Request.getPart(Request.Java:4535)
    at org.Apache.catalina.connector.RequestFacade.getPart(RequestFacade.Java:1095)
    at org.primefaces.component.fileupload.NativeFileUploadDecoder.decodeAdvanced(NativeFileUploadDecoder.Java:60)
    at org.primefaces.component.fileupload.NativeFileUploadDecoder.decode(NativeFileUploadDecoder.Java:37)
    ... 48 more

SEVERE:   javax.servlet.ServletException: The request content-type is not a multipart/form-data
    at org.Apache.catalina.fileupload.Multipart.getPart(Multipart.Java:187)
    at org.Apache.catalina.connector.Request.getPart(Request.Java:4535)
    at org.Apache.catalina.connector.RequestFacade.getPart(RequestFacade.Java:1095)
    at org.primefaces.component.fileupload.NativeFileUploadDecoder.decodeAdvanced(NativeFileUploadDecoder.Java:60)
    at org.primefaces.component.fileupload.NativeFileUploadDecoder.decode(NativeFileUploadDecoder.Java:37)
    at org.primefaces.component.fileupload.FileUploadRenderer.decode(FileUploadRenderer.Java:44)
    at javax.faces.component.UIComponentBase.decode(UIComponentBase.Java:831)
    at javax.faces.component.UIInput.decode(UIInput.Java:771)
    at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.Java:1225)
    at javax.faces.component.UIInput.processDecodes(UIInput.Java:676)
    at javax.faces.component.UIForm.processDecodes(UIForm.Java:225)
    at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.Java:1220)
    at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.Java:1220)
    at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.Java:929)
    at com.Sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.Java:78)
    at com.Sun.faces.lifecycle.Phase.doPhase(Phase.Java:101)
    at com.Sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.Java:198)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.Java:646)
    at org.Apache.catalina.core.StandardWrapper.service(StandardWrapper.Java:1682)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:344)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:214)
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.Java:70)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:256)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:214)
    at filter.NoCacheFilter.doFilter(NoCacheFilter.Java:28)
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:256)
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:214)
    at org.Apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:316)
    at org.Apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java:160)
    at org.Apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.Java:734)
    at org.Apache.catalina.core.StandardPipeline.invoke(StandardPipeline.Java:673)
    at com.Sun.enterprise.web.WebPipeline.invoke(WebPipeline.Java:99)
    at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:174)
    at org.Apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.Java:357)
    at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:260)
    at com.Sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.Java:188)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.Java:191)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.Java:168)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.Java:189)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.Java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.Java:288)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.Java:206)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.Java:136)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.Java:114)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.Java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.Java:838)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.Java:113)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.Java:115)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.Java:55)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.Java:135)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.Java:564)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.Java:544)
    at Java.lang.Thread.run(Thread.Java:722)

Cela ne peut fonctionner que lorsque l'attribut ajax du bouton de commande est défini sur false - ajax="false".


J'ai rétrogradé la version Mojarra à 2.1.9 dans Tomcat 7.0.35. Il a fonctionné avec cette version de Mojarra avec PrimeFaces 4.0 final (et PrimeFaces 4.0 RC1 aussi) - fichiers téléchargés avec une demande AJAX.

J'ai également essayé les versions suivantes de Mojarra

  • 2.2.0
  • 2.2.1
  • 2.2.2
  • 2.2.3
  • 2.2.4

dans GlassFish 4.0 mais aucun d'entre eux n'a réussi à télécharger des fichiers avec une demande AJAX qui est fortement requise car la modification des lignes à l'aide de <p:rowEditor/> (ainsi que les images de chaque ligne, par exemple) dans PrimeFaces DataTable est toujours AJAX based.

Je veux garder GlassFish 4.0 de toute façon. J'ai également essayé de rétrograder Mojarra 2.1.9 dans GlassFish 4.0 mais il n'a pas réussi à créer des bundles se terminant par une exception. GlassFish 4.0 ne semble pas fonctionner avec Mojarra inférieur à 2.2.x.

Alors, quel est responsable de cette exception - PrimeFaces ou JSF? Juste confus. Existe-t-il une solution de contournement pour télécharger des fichiers avec des demandes AJAX dans cet environnement donné?


MODIFIER:

Mappage de filtre dans web.xml:

<filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

<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>*.jsf</url-pattern>
</servlet-mapping>

Le problème reste stationnaire avec la version Mojarra 2.2.5 (ou api , - impl ) publié le 08 janvier 2014.


Encore une fois essayé sur la version Mojarra 2.2.6 (ou api , impl ) publié le 04 mars 2014. Le problème reste intact.


Ne fonctionne toujours pas sur PrimeFaces 5.0 final publié le 05 mai 2014.

28
Tiny

J'ai eu le même problème. Il semble être plus lié au composant <p:commandButton> Qu'au composant <p:fileUpload>, Car il fonctionne avec un <h:commandButton> (Même avec ajax).

Tu pourrais essayer:

<h:commandButton id="btnSubmit" actionListener="#{testManagedBean.insert}" value="Save">
    <f:ajax execute="@all" render="@form"/>
</h:commandButton> 

Je ne peux pas vous dire pourquoi ni comment cela fonctionne, mais cela a résolu le problème pour moi. L'inconvénient est bien sûr que vous devez faire le style vous-même, au moins jusqu'à ce que les gars de Primefaces résolvent ce problème.

MODIFIER :

Après avoir creusé dans les sources et fait un débogage, je me suis rendu compte qu'il y avait en fait deux requêtes (j'ai essayé dans <p:wizard/>). Le premier est le multipart/form-data Qui effectue le téléchargement du fichier. Il déclenche le fichierUploadEvent dans le bean. Si les assistants bouton suivant sont pressés, un autre formulaire avec enctype application/www-urlencoded Est soumis. Cela provoque l'exception. La conclusion est que, contrairement à ce que j'ai écrit dans le commentaire, la suppression de l'exception est une solution valable. Cela peut même être fait d'une manière qui n'inclut pas de changer le Primefaces.jar, ce qui est pratique si les gars résolvent le problème dans une future version.

Voici donc ce qui doit être fait:

  • Créez une nouvelle classe com.yourpackage.fileupload.FileUploadRenderer
  • Copiez et collez le code suivant dans votre nouvelle classe:

    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");
        }
    }
    
  • Ajoutez les lignes suivantes au bas de votre faces-config.xml:

    <render-kit>
        <renderer>
            <component-family>org.primefaces.component</component-family>
            <renderer-type>org.primefaces.component.FileUploadRenderer</renderer-type>
            <renderer-class>com.yourpackage.fileupload.FileUploadRenderer</renderer-class>
        </renderer>
    </render-kit>
    
  • Vous êtes prêt à partir!

Qu'avons-nous fait? Nous avons créé notre propre FileUploadRenderer qui vérifie si le contentType est vraiment multipart/form-data En utilisant la méthode isMultiPartRequest(). Ce n'est que si cela renvoie vrai que le reste du code est exécuté. Dans tous les autres cas, rien ne se passera, ce qui signifie qu'aucune exception ne sera levée. Si Primefaces résout ce problème, il vous suffit de supprimer les lignes de votre faces-config.xml Pour utiliser sa classe.

Laissez-moi savoir si cela fonctionne pour vous!

MODIFIER

Ce code vérifie si la demande donnée est de type multipart/form-data. Si ce n'est pas le cas, l'exécution est arrêtée. Le code Primefaces d'origine continuerait de toute façon. Comme je l'ai mentionné ci-dessus, si vous téléchargez un fichier à l'intérieur d'un composant Primefaces, il y a en fait deux demandes:

  1. Ajax-FileUpload utilisant le <p:fileUpload/> (Enctype: multipart/form-data)
  2. L'action Ajax dans <p:editRow/> Ou <p:wizard/> (Enctype: application/www-form-urlencoded)

Le premier est géré par le moteur de rendu tandis que le second provoque l'exception dans le code d'origine car le moteur de rendu essaie de gérer quelque chose dont il n'est pas capable. Avec les modifications apportées au code, seuls les formulaires multipart/form-data Sont traités par le moteur de rendu, donc aucune exception ne se produit. IMO c'est clairement un bug dans les sources de Primefaces. Les différences de code ne sont que la méthode private boolean isMultiPartRequest(FacesContext context) et sa seule occurrence dans le code. Heureux de pouvoir vous aider!

34
Kai

Comme Kai l'a souligné à juste titre dans sa réponse sur la question actuelle, le problème est dû au fait que NativeFileUploadDecoder tel qu'utilisé par FileUploadRenderer ne vérifie pas si la demande est un multipart/form-data demande ou non. Cela causera des problèmes lorsque le composant est présent sous une forme sur laquelle une demande ajax "régulière" est soumise. Le CommonsFileUploadDecoder vérifie cela correctement et c'est pourquoi il fonctionne correctement dans JSF 2.1 qui n'avait pas encore d'analyseur de téléchargement de fichier natif.

Sa solution de contournement avec un rendu personnalisé est dans la bonne direction, mais l'approche est assez maladroite. Dans ce cas particulier, il n'est absolument pas nécessaire de copypaster toute la classe composée de plus de 200 lignes juste pour ajouter quelques lignes supplémentaires. Au lieu de cela, étendez exactement cette classe et remplacez exactement la méthode avec une vérification if avant de déléguer au super comme suit:

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);
        }
    }

}

Voilà (gardez ça <renderer-kit> entrée dans faces-config.xml bien que). Il ne sert à rien de poursuivre le décodage si la requête n'est pas une requête multipart. Les parties du fichier ne seraient pas disponibles de toute façon (et il n'y a pas non plus de raison de les restituer à javax.servlet.* API lorsque la même fonctionnalité est facilement disponible via ExternalContext).

51
BalusC

Bien que cela soit ancien et déjà répondu, je voulais partager quelque chose, juste au cas où vous l'auriez manqué: PrimeFaces 4+ a maintenant un paramètre de contexte, que vous pouvez utiliser (dans web.xml) pour choisir manuellement le téléchargeur à utiliser (natif -servlet3 ou communs). Vous pouvez utiliser ceci pour forcer le téléchargement commun comme ceci:

<context-param>
   <param-name>primefaces.UPLOADER</param-name>
   <param-value>commons</param-value>
</context-param>

(Bien sûr, vous avez toujours besoin de FileUploadFilter comme décrit ci-dessus et dans le guide). Voir le Guide de l'utilisateur PrimeFaces pour plus d'informations.

9
Mario B

@BalusC - Votre suggestion pour étendre le FileUploadRenderer existant est très claire. Merci!

Selon la version de JSF que vous utilisez, vous pouvez voir apparaître un iFrame aléatoire. C'est un bug noté ici: JAVASERVERFACES-284

Dans ma première tentative pour résoudre ce problème (sans avoir à mettre à niveau vers 2.2.1), je viens de cacher l'iFrame avec CSS.

#JSFFrameId {
  visibility:hidden;
}

Cela a fonctionné mais pour une raison supplémentaire AJAX soumet ne se déclencherait pas. J'ai ensuite appelé un petit script pour supprimer l'iFrame et cela a résolu le problème.

<h:commandButton id="btnSubmit" action="#{fileUploadController.upload}" value="Save" >
  <f:ajax execute="@all" render="frmMain" onevent="removeIFrame()" />
</h:commandButton> 

JavaScript:

function removeIFrame()
{
  document.getElementById("JSFFrameId").removeNode();
}
2
CodeMonkey

J'ai eu le même problème, dans mon cas, j'ai utilisé le téléchargeur de fichiers primefaces dans un tableau de données, j'ai essayé de modifier l'image existante en utilisant onRowEdit, qui s'est retrouvé avec la même erreur mentionnée ci-dessus. Ensuite, j'ai changé le pot primefaces en version 5.1. Maintenant ça marche bien.

0
user2938903