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

Rod*_*nte 98 jsf file-upload primefaces jsf-2

我正在尝试使用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>
Run Code Online (Sandbox Code Playgroud)

还有豆子:

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

}
Run Code Online (Sandbox Code Playgroud)

我已经在方法上放置了一个断点,但它从未调用过.当使用mode="simple"和时ajax="false",它已被调用,但我希望它在高级模式下工作.我正在使用Netbeans和Glassfish 3.1.

Bal*_*usC 213

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

所有PrimeFaces版本

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

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

  2. 使用时mode="advanced"(即ajax上传,这是默认设置),请确保您<h:head>在(主)模板中有a.这将确保正确包含必要的JavaScript文件.这不是必需的mode="simple"(非Ajax上传),但是这样会破坏其他所有PrimeFaces组件look'n'feel和功能,所以你不想反正错过.

  3. 当使用mode="simple"(即非Ajax上传),然后阿贾克斯必须在任何PrimeFaces命令按钮/链接被禁用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>
Run Code Online (Sandbox Code Playgroud)
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!
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您想要非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>
Run Code Online (Sandbox Code Playgroud)
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!
}
Run Code Online (Sandbox Code Playgroud)

请注意,Ajax相关的属性,如auto,allowTypes,update,onstart,oncomplete,等被忽略mode="simple".因此,在这种情况下指定它们是不必要的.

另请注意,您应该立即在上述方法中读取文件内容,而不是在稍后的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兼容容器上时应该毫不费力),那么你需要手动注册下面的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>
Run Code Online (Sandbox Code Playgroud)

<servlet-name>facesServlet必须在值精确匹配<servlet>的入口javax.faces.webapp.FacesServlet在同一web.xml.所以,如果它是,例如Faces Servlet,那么你需要相应地编辑它以匹配.


PrimeFaces 4.x

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

获取上传的文件内容只有一个潜在的问题UploadedFile#getContents().null当使用本机API而不是Apache Commons FileUpload时,这将返回.你需要UploadedFile#getInputStream()改用.另请参阅如何在p:fileUpload中将上传的图像作为BLOB插入MySQL中?

本机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>
Run Code Online (Sandbox Code Playgroud)

故障排除

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

  1. 只有当你使用PrimeFaces文件上传过滤器:还有一个Filter在你的webapp它运行之前的PrimeFaces文件上传过滤器,并已通过例如呼叫消耗的请求主体getParameter(),getParameterMap(),getReader(),等等.请求正文只能解析一次.在文件上载过滤器完成其工作之前调用其中一个方法时,文件上载过滤器将获得一个空的请求主体.

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

  2. 仅当您使用PrimeFaces文件上传过滤器时:Filter您的webapp中还有另一个在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>
    
    Run Code Online (Sandbox Code Playgroud)
  3. 有一个嵌套的<h:form>.这在HTML中是非法的,并且未指定浏览器行为.浏览器通常不会在提交时发送预期的数据.确保你没有嵌套<h:form>.这完全不管形式如何enctype.只是不要嵌套表格.

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


保存上传的文件

在你最终使用它之后,你的下一个问题应该是"我如何/在哪里保存上传的文件?".好了,继续这里:如何在JSF中保存上传的文件.

  • 另一个原因可能是您没有按照PrimeFaces用户指南在`web.xml`中注册PrimeFaces上传过滤器.你还读过它吗?但这并不能解释为什么`mode ="simple"对你有用. (2认同)
  • 也许过滤器映射不正确.它必须映射到`FacesServlet`的`<servlet-name>`,就像你在`web.xml`中定义的那样.大多数IDE /代码生成器默认为`Faces Servlet`,但它可以是很好的`facesServlet`或更确认命名约定的东西. (2认同)
  • Nevermind通过将commons-fileupload添加到类路径和commons-io来解决它,有没有人说这些库需要?无论如何,现在一切似乎都在起作用,这个方法被调用就像它应该的那样,谢谢. (2认同)

小智 30

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

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>
Run Code Online (Sandbox Code Playgroud)


小智 6

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

删除函数handleFileUpload的Netbeans自动填充参数ie(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>
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

139297 次

最近记录:

6 年,4 月 前