如何使用PrimeFaces p:fileUpload?永远不会调用侦听器方法,或者UploadedFile为null /引发错误/不可用


101

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

Answers:


224

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

所有PrimeFaces版本

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

  1. 需要的enctype属性<h:form>必须设置为multipart/form-data。如果不存在,ajax上传可能就可以了,但是一般的浏览器行为是不确定的,并且取决于表单的组成和Web浏览器的版本。只是始终将其指定为安全起见。

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

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

因此,如果您要(自动)使用ajax支持上传文件(请注意<h:head>!):

<h:form enctype="multipart/form-data">
    <p:fileUpload fileUploadListener="#{bean.upload}" auto="true" /> // for PrimeFaces >= 8.x this should be listener instead of fileUploadListener 
</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!
}

做注意到Ajax相关的属性,如autoallowTypesupdateonstartoncomplete,等被忽略mode="simple"。因此,在这种情况下无需指定它们。

还要注意,您应该立即在上述方法内部读取文件内容,而不是在以后的HTTP请求调用的其他bean方法中读取文件内容。这是因为上载的文件内容是请求范围的,因此在以后的/不同的HTTP请求中不可用。任何在以后的请求中尝试读取它的尝试都很有可能最终会出现java.io.FileNotFoundException在临时文件中。


PrimeFaces 8.x

配置与下面的5.x版本信息相同,但是如果未调用您的监听器,请检查是否调用了attriubute listener(例如,对于8.x之前的版本)fileUploadListener

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兼容容器中时应该毫不费力),那么您需要手动注册以下PrimeFaces文件上传过滤器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>

<servlet-name>facesServlet必须与相同的<servlet>条目中的值完全匹配。因此,如果是例如,则需要对其进行相应的编辑以匹配。javax.faces.webapp.FacesServletweb.xmlFaces Servlet


PrimeFaces 4.x

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

通过来获取上载的文件内容仅存在一个潜在问题UploadedFile#getContents()null当使用本机API代替Apache Commons FileUpload时,它将返回。您需要UploadedFile#getInputStream()改用。另请参见如何在MySQL中将p:fileUpload中上传的图像作为BLOB插入?

本机API的另一个潜在问题将是,当上传组件以某种形式存在时,在该表单上会触发一个不同的“常规” ajax请求,该请求不会处理上传组件。另请参见在PrimeFaces 4.0 / JSF 2.2.x中,文件上传不适用于AJAX-javax.servlet.ServletException:请求内容类型不是multipart / form-data

通过切换到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文件上传过滤器:还有一个Filter在你的webapp它运行之前的PrimeFaces文件上传过滤器,并已通过例如呼叫消耗的请求主体getParameter()getParameterMap()getReader(),等等。一个请求正文只能被解析一次。当您在文件上传过滤器执行其工作之前调用这些方法之一时,文件上传过滤器将获得一个空的请求正文。

    要解决此问题,您需要将<filter-mapping>文件上传过滤器的放在另一个过滤器之前web.xml。如果请求不是multipart/form-data请求,则文件上传过滤器将继续运行,好像什么都没有发生。如果您使用因使用注释而自动添加的过滤器(例如PrettyFaces),则可能需要通过web.xml添加显式排序。请参阅如何使用WAR中的注释定义servlet过滤器的执行顺序

  2. 仅当您使用PrimeFaces文件上传过滤器时:Filter您的Web应用程序中就有另一个在PrimeFaces文件上传过滤器之前运行并已执行了RequestDispatcher#forward()调用。通常,URL重写过滤器(例如PrettyFaces)会执行此操作。这将触发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中保存上传的文件


2
另一个原因可能是您没有web.xml按照《 PrimeFaces用户指南》注册PrimeFaces上传过滤器。反正你读过吗?但是,那不能解释为什么mode="simple"对您有用。
BalusC 2012年

1
是的,我确实读过它,并且已经注册了过滤器,但我只是注意到启动服务器时它给我一个错误“严重:WebModule [/ EventsCalendary] PWC1270:异常启动过滤器PrimeFaces FileUpload过滤器”之前注意到它。解决此错误的任何提示吗?
Rodrigo Cavalcante 2012年

2
过滤器映射可能不正确。这对被映射<servlet-name>FacesServlet是你在definied web.xml。大多数IDE /代码生成器将其默认设置为Faces Servlet,但可以将其设置为默认值,也可以facesServlet更好地使用。
BalusC 2012年

2
Nevermind通过在类路径和commons-io中添加commons-fileupload来解决它,有没有人说需要这些库?无论如何,一切似乎现在都在工作,该方法的调用就像应该的那样,谢谢。
Rodrigo Cavalcante 2012年

1
因此,一切都想出了局面,我蚂蚁相同的配置在TomEE和JBoss .. forum.primefaces.org/viewtopic.php?f=3&t=43798
梅德·亚历山德罗夫

30

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

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

与OCP Rewrite一起使用时,这仍然是一个问题。我欠你啤酒:)
Babl 2016年

7

我注意到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>


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>

参数值必须是这3个值中的1个,但不是全部!可以删除整个context-param部分,默认为auto


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公共类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>

你能解释为什么这是答案吗?这只是代码,不是说明或其他内容
库克尔杰(Kukeltje)

“#{bean.uploadFile}”与“#{bean.uploadFasta}”,删除update =“ messages”,它将(仅)对我有用!
romsky '18

0

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

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

然后,在web.xml中的我的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>

0

由于我拥有本文中描述的所有配置,因此我遇到了同样的问题,但是在我的情况下,因为我有两个jquery导入(其中一个是primefaces的查询),导致上传文件时发生冲突。

请参阅Primefaces Jquery冲突


那时您没有在浏览器开发者控制台中收到特定错误吗?
库克尔杰(Kukeltje)

@Kukeltje这是控制台显示:遗漏的类型错误:对象的翻译:有没有方法“文件上传”
基督教阿尔塔米拉诺阿亚拉

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>

这是解决错误的过滤器配置/顺序的方法。
BalusC

嗨@BalusC,您能给我们更多的解释吗?有没有比解决此问题更好的方法?
Xavier Lambros

看到我在这个问题上的答案。
BalusC

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>

应该?如果没有,您会得到特定的错误吗?
库奇特耶

是的,没有此更改,我的FileUploadEvent不会调用。
Alex D

那不是一个明显的错误,那是意外的行为
Kukeltje
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.