wake-up-neo.com

Das Hochladen von Dateien funktioniert nicht mit AJAX in PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: Der Anforderungsinhaltstyp ist kein mehrteiliges Formular

Wichtig: Das in diesem Thread behandelte Problem wurde behoben ab PrimeFaces 5.1 final (Community-Veröffentlichung) veröffentlicht am Montag, den 6. Oktober 2014 (erst vor wenigen Minuten). Ich habe es mit JSF 2.2.8-02 (oder api versucht , impl ).

Als solches, wenn Sie diese Version verwenden (oder höher, nicht zu erwähnen), müssten Sie diese Frage nicht einmal mehr lesen.


Ich habe eine Webanwendung, auf der ausgeführt wird

  • GlassFish 4.0
  • Mojarra 2.2.4
  • PrimeFaces 4.0 final

Alles außer dem Hochladen von Dateien mit AJAX funktioniert gut. Die folgende xhtml-Datei sendet mehrteilige Inhalte über eine AJAX Anfrage, die von einer PrimeFaces-Befehlsschaltfläche ausgelöst wird.

<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>

Die testverwaltete Bean:

@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.");
        }
    }
}

Wenn eine Datei von einem Dateibrowser hochgeladen wird, wird der Dateiname in ihrem Listener angezeigt - fileUploadListener().

Wenn nach dem Hochladen einer Datei die angegebene Befehlstaste gedrückt wird (ajax="true"), Wird die folgende Ausnahme ausgelöst.

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)

Dies kann nur funktionieren, wenn das Ajax-Attribut der Befehlsschaltfläche auf false gesetzt ist - ajax="false".


Ich habe die Mojarra-Version in Tomcat 7.0.35 auf 2.1.9 heruntergestuft. Es funktionierte mit dieser Mojarra-Version zusammen mit PrimeFaces 4.0 final (und PrimeFaces 4.0 RC1 auch) - Dateien, die mit einer AJAX Anfrage) hochgeladen wurden.

Ich habe alternativ folgende Mojarra-Versionen ausprobiert

  • 2.2.0
  • 2.2.1
  • 2.2.2
  • 2.2.3
  • 2.2.4

in GlassFish 4.0 ist es jedoch keinem von ihnen gelungen, Dateien mit einer AJAX) - Anforderung hochzuladen, die dringend erforderlich ist, da Zeilen mit <p:rowEditor/> bearbeitet werden (z. B. zusammen mit Bildern in jeder Zeile). In PrimeFaces basiert DataTable immer auf AJAX.

Ich möchte GlassFish 4.0 trotzdem behalten. Ich habe auch versucht, Mojarra 2.1.9 in GlassFish 4.0 herunterzustufen, aber es konnten keine Bundles erstellt werden, die mit einer Ausnahme enden. GlassFish 4.0 scheint nicht mit Mojarra niedriger als 2.2.x zu funktionieren.

Was ist für die Auslösung dieser Ausnahme verantwortlich - PrimeFaces oder JSF? Nur verwirrt. Gibt es eine Problemumgehung zum Hochladen von Dateien mit AJAX Anforderungen in dieser Umgebung?


EDIT:

Filterzuordnung in 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>

Das Problem bleibt zusammen mit der Mojarra-Version stationär. 2.2.5 (oder api , - impl ) veröffentlicht am 08. Januar 2014.


Nochmals versucht auf der Mojarra-Version 2.2.6 (oder api , impl ) veröffentlicht am 04. März 2014. Das Problem bleibt bestehen.


Funktioniert immer noch nicht auf PrimeFaces 5.0 final veröffentlicht am 5. Mai 2014.

28
Tiny

Ich hatte das gleiche Problem. Es scheint mehr mit dem <p:commandButton> Als mit der <p:fileUpload> - Komponente zu tun zu haben, da es mit einem <h:commandButton> (Auch mit Ajax) funktioniert.

Du könntest es versuchen:

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

Ich kann Ihnen nicht sagen, warum oder wie es funktioniert, aber es hat das Problem für mich behoben. Der Nachteil ist natürlich, dass Sie das Styling selbst vornehmen müssen, zumindest bis die Primefaces-Leute dieses Problem beheben.

EDIT :

Nachdem ich in den Quellen gebuddelt und einige Fehler behoben hatte, stellte ich fest, dass tatsächlich zwei Anfragen gestellt wurden (ich habe es mit <p:wizard/> Versucht). Der erste ist der multipart/form-data, Der den Dateiupload ausführt. Es löst das fileUploadEvent in der Bean aus. Ich den Assistenten nächste Taste gedrückt wird ein anderes Formular mit Enctype application/www-urlencoded Eingereicht wird. Dies verursacht die Ausnahme. Die Schlussfolgerung ist, dass im Gegensatz zu dem, was ich in dem Kommentar zur Unterdrückung der Ausnahme geschrieben habe, eine gültige Lösung ist. Dies kann sogar auf eine Art und Weise erfolgen, bei der die Primefaces.jar nicht geändert wird. Dies ist praktisch, wenn die Jungs das Problem in einer zukünftigen Version beheben.

Folgendes muss also getan werden:

  • Erstelle eine neue Klasse com.yourpackage.fileupload.FileUploadRenderer
  • Kopieren Sie den folgenden Code und fügen Sie ihn in Ihre neue Klasse ein:

    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");
        }
    }
    
  • Fügen Sie die folgenden Zeilen am unteren Rand Ihres faces-config.xml Ein:

    <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>
    
  • Du bist bereit zu gehen!

Was haben wir getan? Wir haben unseren eigenen FileUploadRenderer erstellt, der mit der Methode isMultiPartRequest() prüft, ob der contentType wirklich multipart/form-data Ist. Nur wenn dies wahr ist, wird der Rest des Codes ausgeführt. In jedem anderen Fall passiert nichts, was bedeutet, dass keine Ausnahme geworfen wird. Wenn Primefaces dieses Problem behebt, müssen Sie nur die Zeilen aus Ihrem faces-config.xml Entfernen, um ihre Klasse zu verwenden.

Lassen Sie mich wissen, ob das bei Ihnen funktioniert!

EDIT

Dieser Code prüft, ob die angegebene Anfrage vom Typ Multipart/Formulardaten ist. Ist dies nicht der Fall, wird die Ausführung gestoppt. Der ursprüngliche Primefaces-Code würde trotzdem fortgesetzt. Wie oben erwähnt, werden beim Hochladen einer Datei in einer Primefaces-Komponente zwei Anforderungen gestellt:

  1. Der Ajax-FileUpload mit dem <p:fileUpload/> (Enctype: multipart/form-data)
  2. Die Ajax-Aktion in <p:editRow/> Oder <p:wizard/> (Enctype: application/www-form-urlencoded)

Der erste wird vom Renderer verarbeitet, während der zweite die Ausnahme im ursprünglichen Code verursacht, da der Renderer versucht, etwas zu verarbeiten, zu dem er nicht in der Lage ist. Mit den im Code vorgenommenen Änderungen werden nur multipart/form-data - Formulare vom Renderer verarbeitet, sodass keine Ausnahmen auftreten. IMO ist es eindeutig ein Fehler in den Quellen von Primefaces. Die Codeunterschiede sind nur die Methode private boolean isMultiPartRequest(FacesContext context) und ihr einziges Vorkommen im Code. Ich bin froh, dass ich dir helfen konnte!

34
Kai

Wie Kai in seine Antwort zu Recht auf die aktuelle Frage hingewiesen hat, wird das Problem dadurch verursacht, dass NativeFileUploadDecoder wie von FileUploadRenderer verwendet nicht überprüft wird, ob es sich bei der Anforderung um eine multipart/form-data-Anforderung handelt oder nicht. Dies führt zu Problemen, wenn die Komponente in einer Form vorliegt, in der eine "reguläre" Ajax-Anforderung gesendet wird. Das CommonsFileUploadDecoder prüft das korrekt und deshalb funktioniert es auch in JSF 2.1, das noch keinen nativen Parser zum Hochladen von Dateien hatte.

Seine Lösung, dies mit einem benutzerdefinierten Renderer zu umgehen, ist in die richtige Richtung, der Ansatz ist jedoch ziemlich umständlich. In diesem speziellen Fall ist es absolut nicht erforderlich, die gesamte Klasse, die aus mehr als 200 Zeilen besteht, zu kopieren, um nur ein paar weitere Zeilen hinzuzufügen. Erweitern Sie stattdessen genau diese Klasse und überschreiben Sie genau die Methode mit einem If-Check, bevor Sie an den Super delegieren:

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

}

Das war's (behalte aber diesen <renderer-kit>-Eintrag in faces-config.xml). Es hat keinen Sinn, die Dekodierung fortzusetzen, wenn es sich bei der Anfrage nicht um eine multipart Anfrage handelt. Die Dateiteile wären ohnehin nicht verfügbar (und es gibt auch keinen Grund, auf die javax.servlet.*-API zurückzugreifen, wenn dieselbe Funktionalität über ExternalContext verfügbar ist).

51
BalusC

Obwohl dies alt ist und bereits beantwortet wurde, wollte ich etwas mitteilen, für den Fall, dass Sie es verpasst haben: PrimeFaces 4+ hat jetzt einen Kontextparameter, mit dem Sie (in web.xml) manuell auswählen können, welcher Uploader verwendet werden soll (nativ) -servlet3 oder commons). Sie können dies verwenden, um einen Commons-Uploader wie folgt zu erzwingen:

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

(Natürlich benötigen Sie noch FileUploadFilter wie oben und in der Anleitung beschrieben). Weitere Informationen finden Sie im PrimeFaces-Benutzerhandbuch.

9
Mario B

@BalusC - Ihr Vorschlag zur Erweiterung des vorhandenen FileUploadRenderer ist sehr sauber. Vielen Dank!

Abhängig von der verwendeten JSF-Version wird möglicherweise ein zufälliges iFrame-Popup angezeigt. Dies ist ein Fehler, der hier bemerkt wird: JAVASERVERFACES-284

Bei meinem ersten Versuch, dies zu beheben (ohne ein Upgrade auf 2.2.1 durchführen zu müssen), habe ich den iFrame nur mit CSS ausgeblendet.

#JSFFrameId {
  visibility:hidden;
}

Dies funktionierte, aber aus irgendeinem Grund wurden zusätzliche AJAX Submits nicht ausgelöst. Ich habe dann ein kleines Skript aufgerufen, um den iFrame zu entfernen, und das hat das Problem behoben.

<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

Ich hatte das gleiche Problem. In meinem Fall habe ich den Primefaces-Datei-Uploader in einer Datentabelle verwendet und versucht, das vorhandene Bild mithilfe von onRowEdit zu ändern. Am Ende wurde der oben erwähnte Fehler festgestellt. Dann habe ich das Primefaces-Glas auf die 5.1-Version geändert. Jetzt funktioniert es gut.

0
user2938903