文件上傳不適用於PrimeFaces 4.0 / JSF 2.2.x中的AJAX - javax.servlet.ServletException:請求內容類型不是multipart / form-data


Answers

正如Kai在他對當前問題的回答中正確指出的那樣,問題是由FileUploadRenderer使用的NativeFileUploadDecoder引起的,而不是檢查請求是否是multipart/form-data請求。 當組件以提交“常規”ajax請求的形式存在時,這將導致麻煩。 CommonsFileUploadDecoder正確地檢查它,這就是它在JSF 2.1中正常工作的原因,它還沒有原生文件上傳解析器。

他使用自定義渲染器解決此問題的解決方案是正確的方向,但這種方法非常笨拙。 在這個特殊情況下,絕對不需要復制包含超過200行的整個類只是為了添加更多行。 相反,只需擴展該類,並在委託給super之前使用if檢查完全覆蓋該方法,如下所示:

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

}

就是這樣(儘管在faces-config.xml保留<renderer-kit>條目)。 如果請求不是multipart請求,則無需繼續解碼。 無論如何文件部分都不可用(並且當通過ExternalContext可以獲得相同的功能時,也沒有回送到javax.servlet.* API的重點)。

Question

重要提示:自2014年10月6日星期一(幾分鐘前) releasedPrimeFaces 5.1 final (社區發布)以來,此主題中討論的問題已得到fixed 。 我嘗試了JSF 2.2.8-02 (或apiimpl )。

因此,如果您碰巧使用該版本( 或更高版本,無需提及 ),您甚至不需要再閱讀此問題了。

我正在運行一個Web應用程序

  • GlassFish 4.0
  • Mojarra 2.2.4
  • PrimeFaces 4.0決賽

除了使用AJAX上傳文件外,其他一切都運行良好。 以下xhtml文件通過PrimeFaces命令按鈕觸發的AJAX請求發送多部分內容。

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

測試託管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.");
        }
    }
}

從文件瀏覽器上載文件時,它會在其偵聽器中顯示文件名fileUploadListener()

上傳文件後,當按下給定的命令按鈕( ajax="true" )時,它會引發以下異常。

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)

它只能在命令按鈕的ajax屬性設置為false時起作用 - ajax="false"

我已將Tomcat 7.0.35中的Mojarra版本降級為2.1.9。 它與此Mojarra版本以及PrimeFaces 4.0 final(以及PrimeFaces 4.0 RC1)一起工作 - 使用AJAX請求上傳的文件。

我曾嘗試過以下Mojarra版本

  • 2.2.0
  • 2.2.1
  • 2.2.2
  • 2.2.3
  • 2.2.4

在GlassFish 4.0中,但沒有一個成功上傳帶有AJAX請求的文件,這是非常必要的,因為在PrimeFaces DataTable中使用<p:rowEditor/> (以及每行中的圖像)編輯行總是基於AJAX。

無論如何,我想保留GlassFish 4.0 。 我還嘗試在GlassFish 4.0中降級Mojarra 2.1.9,但它無法創建以異常結尾的bundle。 GlassFish 4.0似乎不適用於低於2.2.x的Mojarra。

那麼,造成這種異常的原因是什麼 - PrimeFaces或JSF? 只是困惑。 在這個給定的環境中,是否有任何解決方法可以上傳帶有AJAX請求的文件?

編輯:

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>

隨著2014年1月8日released的Mojarra 2.2.5版(或apiimpl )問題,該問題仍然存在。

再次嘗試2014年3月4日released的Mojarra 2.2.6版(或apiimpl )。問題依然存在。

仍然無法在released年5月5日released PrimeFaces 5.0最終releasedreleased




@BalusC - 您對擴展現有FileUploadRenderer建議非常簡潔。 謝謝!

根據您使用的JSF版本,您可能會看到隨機彈出的iFrame。 這是一個錯誤: JAVASERVERFACES-2843

在我第一次嘗試解決此問題時(無需升級到2.2.1)我只是用CSS隱藏了iFrame。

#JSFFrameId {
  visibility:hidden;
}

這工作但由於某種原因,其他AJAX提交不會觸發。 然後我調用了一個小腳本來刪除iFrame並解決了問題。

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



Related