jsf - 如何使用PrimeFaces p:fileUpload? 從不調用監聽器方法,或者UploadedFile為空/引發錯誤/不可用





file-upload jsf-2 (8)


你也使用漂亮的臉? 然後將調度程序設置為FORWARD:

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>

我試圖使用PrimeFaces上傳文件,但是在上傳完成後不會調用fileUploadListener方法。

這是觀點:

<h:form>
    <p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload}"
        mode="advanced" 
        update="messages"
        sizeLimit="100000" 
        allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>

    <p:growl id="messages" showDetail="true"/>
</h:form>

豆:

@ManagedBean
@RequestScoped
public class FileUploadController {

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

}

我在該方法上放置了一個斷點,但它從來沒有被調用過。 當使用mode="simple"ajax="false" ,它被調用,但我希望它在高級模式下工作。 我正在使用Netbeans和Glassfish 3.1。




我對primefaces 5.3有同樣的問題,並且經歷了BalusC描述的所有要點,但沒有任何結果。 我遵循他的調試FileUploadRenderer#decode()的建議,我發現我的web.xml設置不正確

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

參數值必須是這3個值中的1個,但不是全部! 整個上下文參數部分可以被刪除,默認是自動的




我注意到Primefaces 3.4和Netbeans 7.2的一點:

刪除函數handleFileUpload的Netbeans自動填充參數,即(事件),否則事件可能為空。

<h:form>
    <p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload(event)}"
        mode="advanced" 
        update="messages"
        sizeLimit="100000" 
        allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>

    <p:growl id="messages" showDetail="true"/>
</h:form>



看起來像javax.faces.SEPARATOR_CHAR不能等於_




如何配置和排除<p:fileUpload>故障取決於PrimeFaces版本。

所有PrimeFaces版本

以下要求適用於所有PrimeFaces版本:

  1. 需要將<h:form>enctype屬性設置為multipart/form-data 。 如果不存在,ajax上傳可能會正常工作,但一般的瀏覽器行為是未指定的,並且取決於表單組成和webbrowser make / version。 只要始終指定它在安全的一面。

  2. 當使用mode="advanced" (即ajax上傳,這是默認)時,確保你在(master)模板中有一個<h:head> 。 這將確保正確包含必要的JavaScript文件。 這對於mode="simple" (非ajax上傳)不是必需的,但這會破壞所有其他PrimeFaces組件的look'n'feel和功能,所以您不想錯過這一點。

  3. 當使用mode="simple" (即非ajax上傳)時,必須在任何PrimeFaces命令按鈕/鏈接上通過ajax="false"禁用ajax="false" ,並且必須使用<p:fileUpload value><p:commandButton action>而不是<p:fileUpload fileUploadListener>

所以,如果你想用ajax支持(自動)上傳文件(記住<h:head> !):

<h:form enctype="multipart/form-data">
    <p:fileUpload fileUploadListener="#{bean.upload}" auto="true" />
</h:form>
public void upload(FileUploadEvent event) {
    UploadedFile uploadedFile = event.getFile();
    String fileName = uploadedFile.getFileName();
    String contentType = uploadedFile.getContentType();
    byte[] contents = uploadedFile.getContents(); // Or getInputStream()
    // ... Save it, now!
}

或者,如果你想要非ajax文件上傳:

<h:form enctype="multipart/form-data">
    <p:fileUpload mode="simple" value="#{bean.uploadedFile}" />
    <p:commandButton value="Upload" action="#{bean.upload}" ajax="false" />
</h:form>
private UploadedFile uploadedFile; // +getter+setter

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

請注意, mode="simple"忽略與ajax相關的屬性,例如autoallowTypesupdateonstartoncomplete等。 所以在這種情況下無需指定它們。

另外請注意,您應該立即在上述方法中讀取文件內容,而不是在稍後的HTTP請求調用的其他bean方法中。 這是因為上傳的文件內容是請求作用域,因此在稍後的/不同的HTTP請求中不可用。 在稍後的請求中讀取它的任何嘗試最可能以臨時文件上的java.io.FileNotFoundException結束。

PrimeFaces 5.x

如果您使用的是JSF 2.2,並且您的faces-config.xml也聲明符合JSF 2.2版本,則不需要任何其他配置。 根本不需要PrimeFaces文件上傳過濾器。 如果您不清楚如何根據所使用的目標服務器正確安裝和配置JSF ,請轉到如何通過Maven正確安裝和配置JSF庫? 和我們的JSF wiki頁面上的“安裝JSF”部分 。

如果你還沒有使用JSF 2.2並且你不能升級它(當你已經在一個Servlet 3.0兼容的容器上時,應該毫不費力),那麼你需要在web.xml手動註冊下面的PrimeFaces文件上傳過濾器(它會解析多部分請求並填充常規請求參數映射,以便FacesServlet可以照常繼續工作):

<filter>
    <filter-name>primeFacesFileUploadFilter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>primeFacesFileUploadFilter</filter-name>
    <servlet-name>facesServlet</servlet-name>
</filter-mapping>

facesServlet<servlet-name>值必須完全匹配相同web.xml javax.faces.webapp.FacesServlet<servlet>條目中的值。 所以如果它是例如Faces Servlet ,那麼你需要相應地編輯它以匹配。

PrimeFaces 4.x

PrimeFaces 5.x也適用於4.x。

通過UploadedFile#getContents()獲取上傳的文件內容只有一個潛在的問題。 當使用本地API代替Apache Commons FileUpload時,這將返回null 。 您需要使用UploadedFile#getInputStream() 。 另請參見如何在p:fileUpload中將上傳的圖像作為BLOB插入到MySQL中?

本機API的另一個潛在問題是,當上傳組件存在於一個表單中時,它會觸發不同的“常規”ajax請求,而不處理上傳組件。 另請參見PrimeFaces 4.0 / JSF 2.2.x中的文件上載不適用於AJAX - javax.servlet.ServletException:請求內容類型不是多部分/表單數據

切換到Apache Commons FileUpload也可以解決這兩個問題。 詳細信息請參見PrimeFaces 3.x部分。

PrimeFaces 3.x

此版本不支持JSF 2.2 / Servlet 3.0本機文件上傳。 您需要手動安裝Apache Commons FileUpload並在web.xml顯式註冊文件上載過濾器。

您需要以下庫:

這些必須存在於webapp的運行時類路徑中。 在使用Maven時,確保它們至少在運行時範圍內(編譯的默認範圍也很好)。 手動攜帶JAR時,確保它們最終位於/WEB-INF/lib文件夾中。

文件上傳過濾器註冊詳細信息可以在上面的PrimeFaces 5.x部分找到。 如果你使用的是PrimeFaces 4+,並且你想顯式地使用Apache Commons FileUpload而不是JSF 2.2 / Servlet 3.0本地文件上傳,那麼你需要在提到的庫旁邊並過濾web.xml的下面的上下文參數:

<context-param>
    <param-name>primefaces.UPLOADER</param-name>
    <param-value>commons</param-value><!-- Allowed values: auto, native and commons. -->
</context-param>

故障排除

如果它仍然不起作用,這裡是與PrimeFaces配置無關的另一個可能的原因:

  1. 只有當您使用PrimeFaces文件上傳過濾器時:您的Web應用Filter中還有另一個Filter ,它 PrimeFaces文件上傳過濾器之前運行並且已通過調用getParameter()getParameterMap()getReader()等消耗過請求主體。 請求主體只能被解析一次。 在文件上傳過濾器執行其作業之前調用其中一種方法時,文件上載過濾器將獲得一個空的請求主體。

    為了解決這個問題,您需要將文件上傳過濾器的<filter-mapping>放在web.xml的其他過濾器之前 。 如果請求不是multipart/form-data請求,則文件上載過濾器將繼續,就像沒有任何事情發生一樣。 如果您使用自動添加的過濾器,因為它們使用註釋(例如PrettyFaces),則可能需要通過web.xml添加顯式排序。 請參閱如何使用WAR中的註釋定義servlet過濾器的執行順序

  2. 只有當您使用PrimeFaces文件上傳過濾器時:您的Web應用Filter中還有另一個Filter ,它 PrimeFaces文件上載過濾器之前運行並執行了RequestDispatcher#forward()調用。 通常,諸如PrettyFaces類的URL重寫過濾器會這樣做。 這會觸發FORWARD調度程序,但過濾器僅在REQUEST調度程序上默認偵聽。

    要解決這個問題,您需要將PrimeFaces文件上傳過濾器放在轉發過濾器之前 ,或者重新配置PrimeFaces文件上傳過濾器以在FORWARD調度器上進行監聽:

    <filter-mapping>
        <filter-name>primeFacesFileUploadFilter</filter-name>
        <servlet-name>facesServlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    
  3. 有一個嵌套的<h:form> 。 這在HTML中是非法的,並且瀏覽器行為未指定。 瀏覽器通常不會在提交時發送預期數據。 確保你沒有嵌套<h:form> 。 這完全與表單的enctype無關。 根本不要嵌套形式。

如果您仍然遇到問題,那麼請調試HTTP流量。 打開網頁瀏覽器的開發者工具集(在Chrome / Firebug23 + / IE9 +中按F12)並檢查網絡/網絡部分。 如果HTTP部分看起來不錯,那麼調試JSF代碼。 在FileUploadRenderer#decode()上放置一個斷點並從那裡前進。

保存上傳的文件

在你終於開始工作之後,你的下一個問題可能應該是“我如何保存上傳的文件?”。 那麼,繼續這裡: 如何在JSF中保存上傳的文件




我有同樣的問題,因為我有這個帖子中描述的所有配置,但在我的情況是因為我有兩個jQuery導入(其中一個是primefaces的查詢),導致衝突上載文件。

見Primefaces jQuery的衝突




這兩個建議對我都沒有幫助。 所以我不得不調試primefaces,發現問題的原因是:

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

然後我在web.xml中添加了一部分內容到我的servlet中。 這樣就解決了這個問題:

<servlet>
    <servlet-name>main</servlet-name>

        <servlet-class>org.apache.myfaces.webapp.MyFacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <multipart-config>
            <location>/tmp</location>
            <max-file-size>20848820</max-file-size>
            <max-request-size>418018841</max-request-size>
            <file-size-threshold>1048576</file-size-threshold>
        </multipart-config>
    </servlet>



url paramters也可以被視為請求參數,因此您也可以訪問

FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()




jsf file-upload jsf-2 primefaces