如何使用PrimeFaces p:fileUpload? Listener方法从不调用,或UploadedFile为空/抛出错误/不可用 [英] How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null / throws an error / not usable

查看:887
本文介绍了如何使用PrimeFaces p:fileUpload? Listener方法从不调用,或UploadedFile为空/抛出错误/不可用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用PrimeFaces上传文件,但上传完成后, fileUploadListener 方法未被调用。



以下是视图:

 < h:form> 
< p:fileUpload fileUploadListener =#{fileUploadController.handleFileUpload}
mode =advanced
update =messages
sizeLimit =100000
allowTypes = /(\ | \ /。)(GIF | JPE G | PNG?)$ //>

< p:growl id =messagesshowDetail =true/>
< / h:表格>

和bean:

  @ManagedBean 
@RequestScoped
public class FileUploadController {
$ b $ public void handleFileUpload(FileUploadEvent event){
FacesMessage msg = new FacesMessage( suecesful,event.getFile()。getFileName()+被上传。);
FacesContext.getCurrentInstance()。addMessage(null,msg);


$ b $ / code $ / pre
$ b $ p我已经放置了一个断点该方法,但它从来没有被调用。当使用 mode =simple ajax =false时,它被调用,但是我希望它在高级模式下工作。我使用的是Netbeans和GlassFish 3.1。如何配置和排除< p:fileUpload>>的问题; 取决于PrimeFaces版本。



所有PrimeFaces版本



到所有PrimeFaces版本:
$ b


  1. enctype c $ c>< h:form> 需要设置为 multipart / form-data 。如果不存在,则ajax上传可能正常工作,但一般的浏览器行为是不确定的,并且取决于表单组成和web浏览器的版本。使用 mode =advanced(())即ajax上传,这是默认的),然后确保(master)模板中有一个< h:head> 。这将确保正确包含必要的JavaScript文件。这对于 mode =simple(非ajax上传)不是必需的,但是这会破坏所有其他PrimeFaces组件的look'n'feel和功能,所以你不要当你使用 mode =simple ajax上传),那么必须在任何PrimeFaces命令按钮/链接上通过 ajax =false禁用ajax,并且必须使用< p: fileUpload value> with < p:commandButton action> 而不是< p:fileUpload fileUploadListener>


  2. $ b
    $ b

     < h:form enctype = < h:head>  多部分/格式数据> 
    < / h:表格>





      public void upload FileUploadEvent事件){
    UploadedFile uploadedFile = event.getFile();
    String fileName = uploadedFile.getFileName();
    String contentType = uploadedFile.getContentType();
    byte [] contents = uploadedFile.getContents(); //或getInputStream()
    // ...保存它,现在!

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

     < h:form enctype =multipart / form-data> 
    < p:fileUpload mode =simplevalue =#{bean.uploadedFile}/>
    < p:commandButton value =Uploadaction =#{bean.upload}ajax =false/>
    < / h:表格>





     私人UploadedFile uploadedFile; // + getter + setter 

    public void upload(){
    String fileName = uploadedFile.getFileName();
    String contentType = uploadedFile.getContentType();
    byte [] contents = uploadedFile.getContents(); //或getInputStream()
    // ...保存它,现在!





    $ b请注意,与ajax相关的属性如 auto , allowTypes update onstart mode =simple中,, oncomplete 忽略。所以在这种情况下不需要指定它们。



    另外请注意,您应该立即读取文件内容,而不是由以后的HTTP请求调用的不同的bean方法。这是因为上传的文件内容是请求范围的,因此在稍后的/不同的HTTP请求中不可用。在稍后的请求中读取它的任何尝试都很可能以临时文件中的 java.io.FileNotFoundException 结束。



    如果您使用的是JSF 2.2,那么您不需要任何额外的配置,您的

    PrimeFaces 5.x



    faces-config.xml 也被声明为符合JSF 2.2版本。根本不需要PrimeFaces文件上传过滤器。如果您不清楚如何根据所使用的目标服务器正确安装和配置JSF,请转至如何通过Maven正确安装和配置JSF库安装JSF部分我们的JSF维基页面
    $ b 如果您还没有使用JSF 2.2,并且您不能升级它(应该在已经开启的时候毫不费力一个Servlet 3.0兼容容器),那么你需要在 web.xml 中手工注册下面的PrimeFaces文件上传过滤器(它将解析多部分请求并填充常规请求参数map,这样 FacesServlet 可以像往常一样继续工作):

     <滤光器> 
    < 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>

    < servlet-name> facesServlet 必须与 javax中的< servlet> 条目中的值完全匹配。 faces.webapp.FacesServlet 在同一个 web.xml 中。所以如果它是例如 Faces Servlet ,那么您需要相应地进行编辑以匹配。






    < h2> 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本地文件上传,那么你需要在提到的库旁边,同时过滤下面的<$ c
    $ b

     < context-param> $ c> web.xml 


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






    疑难解答



    如果它仍然不起作用,这里是与PrimeFaces配置无关的另一个可能的原因:
    $ b


    1. 只有当您使用PrimeFaces文件上传过滤器时:您的webapp中还有另一个过滤器,它在PrimeFaces文件上传过滤器之前运行,并且已经消耗请求体例如调用 getParameter() getParameterMap() getReader()为了解决这个问题,你需要把文件上传过滤器的< filter-mapping> 之前的 web.xml 中的其他过滤器。如果请求不是 multipart / form-data 请求,那么文件上传过滤器就会继续,就像什么都没发生一样。

    2. $ b $只有在使用PrimeFaces文件上传过滤器的情况下:在您的Web应用程序中还有另外一个过滤器,它在之前运行 PrimeFaces文件上传过滤器,并执行了 RequestDispatcher#forward() 调用。通常,URL重写过滤器(例如 PrettyFaces )执行此操作。这会触发 FORWARD 调度程序,但过滤器仅在 REQUEST 调度程序上默认监听。为了解决这个问题,您需要将PrimeFaces文件上传过滤器放在转发过滤器之前,或者重新配置PrimeFaces文件上传过滤器来监听 FORWARD 调度器:

      <过滤器映射>
      < filter-name> primeFacesFileUploadFilter< / filter-name>
      < servlet-name> facesServlet< / servlet-name>
      < dispatcher>请求< /调度器>
      < dispatcher> FORWARD< / dispatcher>
      < / filter-mapping>


  3. 有一个嵌套< h:form> 。这在HTML中是非法的,并且浏览器行为是未指定的。浏览器通常不会在提交时发送预期的数据。确保你没有嵌套< h:form> 。完全不管表单的 enctype 。如果你仍然有问题,那么调试HTTP流量。如果你仍然有问题,那么调试HTTP流量。打开网页浏览器的开发者工具集(在Chrome / Firebug23 + / IE9 +中按F12),然后检查网络/网络部分。如果HTTP部分看起来不错,那么调试JSF代码。在 FileUploadRenderer#decode() 并从那里前进。




    保存上传文件



    工作,你的下一个问题可能应该像我如何保存上传的文件?。那么,继续这里:如何保存上传的文件在JSF


    I'm trying to upload a file using PrimeFaces, but the fileUploadListener method isn't being invoked after the upload finishes.

    Here is the view:

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

    And the bean:

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

    I've placed a breakpoint on the method, but it's never called. When using mode="simple" and ajax="false", it is been invoked, but I want it to work in the advanced mode. I'm using Netbeans and Glassfish 3.1.

    解决方案

    How to configure and troubleshoot <p:fileUpload> depends on PrimeFaces version.

    All PrimeFaces versions

    The below requirements apply to all PrimeFaces versions:

    1. The enctype attribute of the <h:form> needs to be set to multipart/form-data. When this is absent, the ajax upload may just work, but the general browser behavior is unspecified and dependent on form composition and webbrowser make/version. Just always specify it to be on the safe side.

    2. When using mode="advanced" (i.e. ajax upload, this is the default), then make sure that you've a <h:head> in the (master) template. This will ensure that the necessary JavaScript files are properly included. This is not required for mode="simple" (non-ajax upload), but this would break look'n'feel and functionality of all other PrimeFaces components, so you don't want to miss that anyway.

    3. When using mode="simple" (i.e. non-ajax upload), then ajax must be disabled on any PrimeFaces command buttons/links by ajax="false", and you must use <p:fileUpload value> with <p:commandButton action> instead of <p:fileUpload fileUploadListener>.

    So, if you want (auto) file upload with ajax support (mind the <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!
    }
    

    Or if you want non-ajax file upload:

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

    Do note that ajax-related attributes such as auto, allowTypes, update, onstart, oncomplete, etc are ignored in mode="simple". So it's needless to specify them in such case.

    Also note that you should read the file contents immediately inside the abovementioned methods and not in a different bean method invoked by a later HTTP request. This is because the uploaded file contents is request scoped and thus unavailable in a later/different HTTP request. Any attempt to read it in a later request will most likely end up with java.io.FileNotFoundException on the temporary file.


    PrimeFaces 5.x

    This does not require any additional configuration if you're using JSF 2.2 and your faces-config.xml is also declared conform JSF 2.2 version. You do not need the PrimeFaces file upload filter at all. In case it's unclear to you how to properly install and configure JSF depending on the target server used, head to How to properly install and configure JSF libraries via Maven? and "Installing JSF" section of our JSF wiki page.

    If you're however not using JSF 2.2 yet and you can't upgrade it (should be effortless when already on a Servlet 3.0 compatible container), then you need to manually register the below PrimeFaces file upload filter in web.xml (it will parse the multi part request and fill the regular request parameter map so that FacesServlet can continue working as usual):

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

    The <servlet-name> value of facesServlet must match exactly the value in the <servlet> entry of the javax.faces.webapp.FacesServlet in the same web.xml. So if it's e.g. Faces Servlet, then you need to edit it accordingly to match.


    PrimeFaces 4.x

    The same story as PrimeFaces 5.x applies on 4.x as well.

    There's only a potential problem in getting the uploaded file content by UploadedFile#getContents(). This will return null when native API is used instead of Apache Commons FileUpload. You need to use UploadedFile#getInputStream() instead. See also How to insert uploaded image from p:fileUpload as BLOB in MySQL?

    Another potential problem with native API will manifest is when the upload component is present in a form on which a different "regular" ajax request is fired which does not process the upload component. See also 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.

    Both problems can also be solved by switching to Apache Commons FileUpload. See PrimeFaces 3.x section for detail.


    PrimeFaces 3.x

    This version does not support JSF 2.2 / Servlet 3.0 native file upload. You need to manually install Apache Commons FileUpload and explicitly register the file upload filter in web.xml.

    You need the following libraries:

    Those must be present in the webapp's runtime classpath. When using Maven, make sure they are at least runtime scoped (default scope of compile is also good). When manually carrying around JARs, make sure they end up in /WEB-INF/lib folder.

    The file upload filter registration detail can be found in PrimeFaces 5.x section here above. In case you're using PrimeFaces 4+ and you'd like to explicitly use Apache Commons FileUpload instead of JSF 2.2 / Servlet 3.0 native file upload, then you need next to the mentioned libraries and filter also the below context param in web.xml:

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


    Troubleshooting

    In case it still doesn't work, here are another possible causes unrelated to PrimeFaces configuration:

    1. Only if you're using the PrimeFaces file upload filter: There's another Filter in your webapp which runs before the PrimeFaces file upload filter and has already consumed the request body by e.g. calling getParameter(), getParameterMap(), getReader(), etcetera. A request body can be parsed only once. When you call one of those methods before the file upload filter does its job, then the file upload filter will get an empty request body.

      To fix this, you'd need to put the <filter-mapping> of the file upload filter before the other filter in web.xml. If the request is not a multipart/form-data request, then the file upload filter will just continue as if nothing happened.

    2. Only if you're using the PrimeFaces file upload filter: There's another Filter in your webapp which runs before the PrimeFaces file upload filter and has performed a RequestDispatcher#forward() call. Usually, URL rewrite filters such as PrettyFaces do this. This triggers the FORWARD dispatcher, but filters listen by default on REQUEST dispatcher only.

      To fix this, you'd need to either put the PrimeFaces file upload filter before the forwarding filter, or to reconfigure the PrimeFaces file upload filter to listen on FORWARD dispatcher too:

      <filter-mapping>
          <filter-name>primeFacesFileUploadFilter</filter-name>
          <servlet-name>facesServlet</servlet-name>
          <dispatcher>REQUEST</dispatcher>
          <dispatcher>FORWARD</dispatcher>
      </filter-mapping>
      

    3. There's a nested <h:form>. This is illegal in HTML and the browser behavior is unspecified. More than often, the browser won't send the expected data on submit. Make sure that you are not nesting <h:form>. This is completely regardless of the form's enctype. Just do not nest forms at all.

    If you're still having problems, well, debug the HTTP traffic. Open the webbrowser's developer toolset (press F12 in Chrome/Firebug23+/IE9+) and check the Net/Network section. If the HTTP part looks fine, then debug the JSF code. Put a breakpoint on FileUploadRenderer#decode() and advance from there.


    Saving uploaded file

    After you finally got it to work, your next question shall probably be like "How/where do I save the uploaded file?". Well, continue here: How to save uploaded file in JSF.

    这篇关于如何使用PrimeFaces p:fileUpload? Listener方法从不调用,或UploadedFile为空/抛出错误/不可用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆