如何使用PrimeFaces p:fileUpload?从不调用Listener方法或者UploadedFile为null /抛出错误/不可用

时间:2012-01-16 04:37:59

标签: jsf file-upload jsf-2 primefaces

我尝试使用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。

11 个答案:

答案 0 :(得分:206)

如何配置<p:fileUpload>并排除故障取决于PrimeFaces版本。

所有PrimeFaces版本

以下要求适用于所有PrimeFaces版本:

  1. enctype的{​​{1}}属性需要设置为<h:form>。如果不存在,则ajax上传可能正常工作,但一般的浏览器行为未指定,并且取决于表单组成和webbrowser make / version。只需指出它是安全的。

  2. 使用multipart/form-data时(即ajax上传,这是默认设置),请确保您在(主)模板中有mode="advanced"。这将确保正确包含必要的JavaScript文件。 <h:head>(非ajax上传)不需要这样做,但这会破坏所有其他PrimeFaces组件的外观和功能,所以你不想错过它

  3. 使用mode="simple"(即非ajax上传)时,必须在mode="simple"的任何PrimeFaces命令按钮/链接上禁用ajax,并且必须使用ajax="false" <p:fileUpload value>代替<p:commandButton action>

  4. 所以,如果你希望(自动)文件上传支持ajax(请注意<p:fileUpload fileUploadListener>!):

    <h:head>
    <h:form enctype="multipart/form-data">
        <p:fileUpload fileUploadListener="#{bean.upload}" auto="true" />
    </h:form>
    

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

    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!
    }
    
    <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! } autoallowTypesupdateonstart等相关的与ajax相关的属性会被忽略oncomplete。因此,在这种情况下不必指定它们。

    另请注意,您应该在上述方法中立即读取文件内容,而不是在稍后的HTTP请求调用的其他bean方法中。这是因为上载的文件内容是请求范围的,因此在稍后/不同的HTTP请求中不可用。在以后的请求中读取它的任何尝试都很可能在临时文件上以mode="simple"结束。


    PrimeFaces 5.x

    如果您正在使用JSF 2.2并且您的java.io.FileNotFoundException也被声明为符合JSF 2.2版本,则不需要任何其他配置。您根本不需要PrimeFaces文件上传过滤器。如果您不清楚如何根据所使用的目标服务器正确安装和配置JSF,请前往How to properly install and configure JSF libraries via Maven?"Installing JSF" section of our JSF wiki page

    如果你还没有使用JSF 2.2并且你无法升级它(当已经在Servlet 3.0兼容容器上时应该毫不费力),那么你需要手动注册下面的PrimeFaces文件上传过滤器在faces-config.xml中(它将解析多部分请求并填充常规请求参数映射,以便web.xml可以继续照常工作):

    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> 的{​​{1}}值必须与同一<servlet-name>facesServlet的{​​{1}}条目中的值完全匹配。所以如果它是,例如<servlet>,然后您需要相应地进行编辑以匹配。


    PrimeFaces 4.x

    与PrimeFaces 5.x相同的故事同样适用于4.x.

    通过javax.faces.webapp.FacesServlet获取上传的文件内容只是一个潜在的问题。当使用本机API而不是Apache Commons FileUpload时,这将返回web.xml。您需要使用Faces Servlet代替。另请参阅How to insert uploaded image from p:fileUpload as BLOB in MySQL?

    本机API的另一个潜在问题将体现在上传组件以不同的常规表格形式出现的情况下。触发了ajax请求,该请求不处理上传组件。另请参阅File upload doesn't work with AJAX in PrimeFaces 4.0/JSF 2.2.x - javax.servlet.ServletException: The request content-type is not a multipart/form-data

    切换到Apache Commons FileUpload也可以解决这两个问题。有关详细信息,请参阅PrimeFaces 3.x部分。


    PrimeFaces 3.x

    此版本不支持JSF 2.2 / Servlet 3.0本机文件上传。您需要手动安装Apache Commons FileUpload并在UploadedFile#getContents()中明确注册文件上传过滤器。

    您需要以下库:

    这些必须存在于webapp的运行时类路径中。使用Maven时,请确保它们至少是运行时作用域(默认编译范围也很好)。手动携带JAR时,请确保它们最终位于null文件夹中。

    文件上传过滤器注册详细信息可以在上面的PrimeFaces 5.x部分找到。如果您正在使用PrimeFaces 4+并且您想明确使用Apache Commons FileUpload而不是JSF 2.2 / Servlet 3.0本机文件上传,那么您需要在提到的库旁边并过滤下面的上下文参数在UploadedFile#getInputStream()

    web.xml

    故障排除

    如果它仍然无法正常工作,以下是与PrimeFaces配置无关的另一个可能原因:

    1. 仅当您使用PrimeFaces文件上传过滤器时:您的网络应用中还有另一个/WEB-INF/lib在 PrimeFaces文件上传过滤器之前运行已经通过例如消耗了请求体致电web.xml<context-param> <param-name>primefaces.UPLOADER</param-name> <param-value>commons</param-value><!-- Allowed values: auto, native and commons. --> </context-param> Filter等。请求正文只能解析一次。在文件上载过滤器完成其工作之前调用其中一个方法时,文件上载过滤器将获得一个空的请求主体。

      要解决此问题,您需要将文件上传过滤器getParameter()放在 getParameterMap()中的其他过滤器之前。如果请求不是getReader()请求,则文件上载过滤器将继续,就好像什么也没发生一样。如果您使用由于使用注释而自动添加的过滤器(例如,PrettyFaces),则可能需要通过web.xml添加显式排序。请参阅How to define servlet filter order of execution using annotations in WAR

    2. 仅当您使用PrimeFaces文件上传过滤器时:您的网络应用中还有另一个<filter-mapping> PrimeFaces文件上传过滤器之前运行已经进行了RequestDispatcher#forward()电话。通常,URL重写过滤器(例如PrettyFaces)会执行此操作。这会触发web.xml调度程序,但过滤器默认只在multipart/form-data调度程序上侦听。

      要解决此问题,您需要在转发过滤器之前放置PrimeFaces文件上传过滤器,或者重新配置PrimeFaces文件上传过滤器以侦听Filter调度程序太:

      FORWARD
    3. 有一个嵌套的REQUEST。这在HTML中是非法的,并且未指定浏览器行为。浏览器通常不会在提交时发送预期的数据。确保您没有嵌套FORWARD。这完全与表格<filter-mapping> <filter-name>primeFacesFileUploadFilter</filter-name> <servlet-name>facesServlet</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping> 无关。只是不要嵌套表格。

    4. 如果您仍然遇到问题,请调试HTTP流量。打开webbrowser的开发人员工具集(在Chrome / Firebug23 + / IE9 +中按F12)并检查网络/网络部分。如果HTTP部分看起来很好,那么调试JSF代码。在FileUploadRenderer#decode()上设一个断点并从那里前进。


      保存上传的文件

      在你最终开始工作之后,你的下一个问题应该是&#34;我如何/在哪里保存上传的文件?&#34;。好了,继续这里:How to save uploaded file in JSF

答案 1 :(得分:30)

你也在使用prettyfaces?然后将调度程序设置为FORWARD:

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

答案 2 :(得分:6)

有一点我注意到Primefaces 3.4和Netbeans 7.2:

删除函数handleFileUpload的Netbeans自动填充参数,即(event)否则事件可能为null。

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

答案 3 :(得分:2)

看起来javax.faces.SEPARATOR_CHAR不能等于_

答案 4 :(得分:0)

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

param-value必须是这三个值中的一个,但不是全部!! 整个context-param部分可以删除,默认值为 auto < / EM>

答案 5 :(得分:0)

bean.xhtml

    <h:form enctype="multipart/form-data">    
<p:outputLabel value="Choose your file" for="submissionFile" />
                <p:fileUpload id="submissionFile"
                    value="#{bean.file}"
                    fileUploadListener="#{bean.uploadFile}" mode="advanced"
                    auto="true" dragDropSupport="false" update="messages"
                    sizeLimit="100000" fileLimit="1" allowTypes="/(\.|\/)(pdf)$/" />

</h:form>

Bean.java

@ManagedBean

@ViewScoped public class Submission实现Serializable {

private UploadedFile file;

//Gets
//Sets

public void uploadFasta(FileUploadEvent event) throws FileNotFoundException, IOException, InterruptedException {

    String content = IOUtils.toString(event.getFile().getInputstream(), "UTF-8");

    String filePath = PATH + "resources/submissions/" + nameOfMyFile + ".pdf";

    MyFileWriter.writeFile(filePath, content);

    FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
            event.getFile().getFileName() + " is uploaded.", null);
    FacesContext.getCurrentInstance().addMessage(null, message);

}

}

的web.xml

    <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<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>

答案 6 :(得分:0)

这里的建议都没有对我有帮助。所以我不得不调试primefaces并发现问题的原因是:

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

然后我在web.xml中将section添加到了我的face 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>

答案 7 :(得分:0)

我遇到了同样的问题,因为我有这篇文章中描述的所有配置,但在我的情况下是因为我有两个jquery导入(其中一个是primefaces的查询)导致冲突上传文件

See Primefaces Jquery conflict

答案 8 :(得分:0)

对于使用Tomee或Tomcat且无法正常工作的用户,请尝试在 META-INF 中创建 context.xml 并添加 allowCasualMultipartParsing =“ true “

<?xml version="1.0" encoding="UTF-8"?>
<Context allowCasualMultipartParsing="true">
  <!-- empty or not depending your project -->
</Context>

答案 9 :(得分:0)

对于JBoss 7.2(Undertow)和PrimeFaces 6.0,org.primefaces.webapp.filter.FileUploadFilter应该从web.xml中删除,并且上下文参数文件上传器应设置为native:

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

答案 10 :(得分:0)

p:fileUpload 置于 h:form 解决了我的问题。