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

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

问题描述

我正在尝试使用 PrimeFaces 上传文件,但在上传完成后没有调用 fileUploadListener 方法.

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

这是视图:

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

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.

推荐答案

如何配置和故障排除取决于 PrimeFaces 和 JSF 版本.

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

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

The below requirements apply to all PrimeFaces versions:

  1. enctype属性需要设置为multipart/form-data.如果不存在,ajax 上传可能会正常工作,但一般浏览器行为未指定并取决于表单组合和 webbrowser 制作/版本.只是总是指定它是安全的.

  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.

当使用 mode="advanced"(即 ajax 上传,这是默认设置)时,请确保您有 在(主)模板中.这将确保正确包含必要的 JavaScript 文件.mode=simple"(非ajax上传)不需要这,但这会破坏所有其他PrimeFaces组件的外观和功能,所以你不想错过无论如何.

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.

当使用mode=simple"(即非ajax上传)时,必须通过ajax=false"在任何PrimeFaces命令按钮/链接上禁用ajax;,并且您必须使用 而不是 ;.

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

所以,如果你想要(自动)文件上传和 ajax 支持(注意 !):

So, if you want (auto) file upload with ajax support (mind the <h:head>!):

<h:form enctype="multipart/form-data">
    <p:fileUpload listener="#{bean.upload}" auto="true" /> // For PrimeFaces version older than 8.x this should be fileUploadListener instead of listener.
</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文件上传:

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 transient 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" 中被忽略.所以在这种情况下不需要指定它们.

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.

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

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.

配置与下面的 5.x 版本信息相同,但如果您的侦听器未被调用,请检查方法属性是否被称为 listener 而不是(与 8.x 之前的版本一样)<代码>fileUploadListener.

Configuration is identical to the 5.x version info below, but if your listener is not called, check if the method attribute is called listener and not (like with pre 8.x versions) fileUploadListener.

如果您使用的是 JSF 2.2 并且您的 faces-config.xml 也声明为符合 JSF 2.2 版本,则这不需要需要任何额外的配置.您根本不需要需要 PrimeFaces 文件上传过滤器,并且您也不需要web.xml 中的 primefaces.UPLOADER 上下文参数.xml.如果您不清楚如何根据所使用的目标服务器正确安装和配置 JSF,请前往 如何通过 Maven 正确安装和配置 JSF 库?安装 JSF";我们 JSF wiki 页面的部分.

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 and you also do not need the primefaces.UPLOADER context parameter in web.xml. 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.

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

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>

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

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 5.x 相同的故事也适用于 4.x.

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

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

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?

本机 API 的另一个潜在问题是当上传组件以不同的常规"组件的形式存在时.ajax 请求被触发,它不处理上传组件.另见 文件上传不适用于 PrimeFaces 4.0/JSF 2.2.x 中的 AJAX - javax.servlet.ServletException: The request content-type is not a multipart/form-data.

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.

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

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

此版本不支持JSF 2.2/Servlet 3.0原生文件上传.您需要手动安装 Apache Commons FileUpload 并在 web.xml 中显式注册文件上传过滤器.

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.

您需要以下库:

那些必须存在于 web 应用程序的运行时类路径中.使用 Maven 时,请确保它们至少是运行时范围的(编译的默认范围也不错).手动携带 JAR 时,请确保它们最终位于 /WEB-INF/lib 文件夹中.

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.

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

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>


问题排查

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


Troubleshooting

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

  1. 仅当您使用 PrimeFaces 文件上传过滤器时:您的 web 应用程序中有另一个 Filter,它在 PrimeFaces 文件上传过滤器之前运行并且已经消耗了请求正文由例如调用 getParameter()getParameterMap()getReader() 等.一个请求体只能被解析一次.当您在文件上传过滤器执行其工作之前调用这些方法之一时,文件上传过滤器将获得一个空的请求正文.

  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.

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

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. If you use filters that are automagically added because they use annotations (e.g. PrettyFaces), you might need to add explicit ordering via web.xml. See How to define servlet filter order of execution using annotations in WAR

仅当您使用 PrimeFaces 文件上传过滤器时:您的 web 应用程序中还有另一个 Filter,它在 PrimeFaces 文件上传过滤器之前运行并执行了RequestDispatcher#forward() 调用.通常,诸如 PrettyFaces 之类的 URL 重写过滤器会执行此操作.这会触发 FORWARD 调度器,但过滤器默认只监听 REQUEST 调度器.

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.

要解决此问题,您需要将 PrimeFaces 文件上传过滤器置于转发过滤器之前,或者重新配置 PrimeFaces 文件上传过滤器以侦听 FORWARD调度员也是:

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>

  • 有一个嵌套的 .这在 HTML 中是非法的,浏览器行为未指定.通常,浏览器不会在提交时发送预期的数据.确保您没有嵌套 .这完全与表单的 enctype 无关.完全不要嵌套表单.

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

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

    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.

    在您最终让它工作后,您的下一个问题可能类似于我如何/在哪里保存上传的文件?".好吧,继续在这里:如何在 JSF 中保存上传的文件.

    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?从未调用侦听器方法或 UploadedFile 为空/引发错误/不可用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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