![](/img/trans.png)
[英]UploadedFile is null when uploading file with <p:fileUpload mode=“simple”>
[英]How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null / throws an error / not usable
我正在尝试使用 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。
如何配置和排除<p:fileUpload>
故障取决于 PrimeFaces 和 JSF 版本。
以下要求适用于所有 PrimeFaces 版本:
<h:form>
的enctype
属性需要设置为multipart/form-data
。 如果不存在,ajax 上传可能会正常工作,但一般浏览器行为未指定并取决于表单组合和 webbrowser 制作/版本。 只是总是指定它是安全的。
当使用mode="advanced"
(即 ajax 上传,这是默认设置)时,请确保您在(主)模板中有一个<h:head>
。 这将确保正确包含必要的 JavaScript 文件。 这对于mode="simple"
(非 ajax 上传)不是必需的,但这会破坏所有其他 PrimeFaces 组件的外观和功能,因此无论如何您都不想错过它。
当使用mode="simple"
(即非 ajax 上传)时,必须通过ajax="false"
在任何 PrimeFaces 命令按钮/链接上禁用ajax="false"
,并且您必须将<p:fileUpload value>
与<p:commandButton action>
而不是<p:fileUpload listener>
。
所以,如果你想要(自动)带有 ajax 支持的文件上传(注意<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文件上传:
<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!
}
请注意,在mode="simple"
会忽略与 ajax 相关的属性,例如auto
、 allowTypes
、 update
、 onstart
、 oncomplete
等。 所以在这种情况下不需要指定它们。
另请注意,您应该立即在上述方法中读取文件内容,而不是在稍后的 HTTP 请求调用的不同 bean 方法中读取文件内容。 这是因为上传的文件内容是请求范围的,因此在以后/不同的 HTTP 请求中不可用。 任何在以后的请求中读取它的尝试很可能会以临时文件上的java.io.FileNotFoundException
结束。
配置与下面的 5.x 版本信息相同,但如果您的侦听器未被调用,请检查方法属性是否被称为listener
而不是(与 8.x 之前的版本一样) fileUploadListener
。
如果你使用JSF 2.2,你的这不需要任何额外的配置faces-config.xml
还宣称符合JSF 2.2版本。 你不需要PrimeFaces文件上传过滤器在所有的,你也并不需要primefaces.UPLOADER
在上下文参数web.xml
。 如果您不清楚如何根据所使用的目标服务器正确安装和配置 JSF ,请前往如何通过 Maven 正确安装和配置 JSF 库? 和我们 JSF wiki 页面的“安装 JSF”部分。
但是,如果您还没有使用 JSF 2.2 并且您无法升级它(当已经在 Servlet 3.0 兼容容器上时应该毫不费力),那么您需要在web.xml
手动注册以下 PrimeFaces 文件上传过滤器(它将解析多部分请求并填充常规请求参数映射,以便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>
facesServlet
的<servlet-name>
值必须与同一web.xml
javax.faces.webapp.FacesServlet
的<servlet>
条目中的值完全匹配。 因此,如果它是例如Faces Servlet
,那么您需要相应地编辑它以匹配。
与 PrimeFaces 5.x 相同的故事也适用于 4.x。
通过UploadedFile#getContents()
获取上传的文件内容只有一个潜在的问题。 当使用本机 API 而不是 Apache Commons FileUpload 时,这将返回null
。 您需要改用UploadedFile#getInputStream()
。 另请参阅如何在 MySQL 中将 p:fileUpload 上传的图像插入为 BLOB?
本机 API 的另一个潜在问题是当上传组件以不同的“常规”ajax 请求被触发的形式存在时,该请求不处理上传组件。 另请参阅文件上传不适用于 PrimeFaces 4.0/JSF 2.2.x 中的 AJAX - javax.servlet.ServletException: The request content-type is not a multipart/form-data 。
这两个问题也可以通过切换到 Apache Commons FileUpload 来解决。 有关详细信息,请参阅 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 配置无关的另一个可能原因:
仅当您使用 PrimeFaces 文件上传过滤器时:您的 web 应用Filter
中还有另一个Filter
,它在PrimeFaces 文件上传过滤器之前运行,并且已经通过调用getParameter()
、 getParameterMap()
、 getReader()
等消耗了请求正文。 一个请求体只能被解析一次。 当您在文件上传过滤器完成其工作之前调用这些方法之一时,文件上传过滤器将获得一个空的请求正文。
要解决此问题,您需要将文件上传过滤器的<filter-mapping>
放在web.xml
的其他过滤器之前。 如果请求不是multipart/form-data
请求,则文件上传过滤器将继续,好像什么也没发生。 如果您使用自动添加的过滤器,因为它们使用注释(例如 PrettyFaces),您可能需要通过 web.xml 添加显式排序。 请参阅如何使用 WAR 中的注释定义 servlet 过滤器执行顺序
仅当您使用 PrimeFaces 文件上传过滤器时:您的 web 应用Filter
中有另一个Filter
,它在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>
有一个嵌套的<h:form>
。 这在 HTML 中是非法的,并且未指定浏览器行为。 通常,浏览器不会在提交时发送预期的数据。 确保您没有嵌套<h:form>
。 这完全与表单的enctype
无关。 只是不要嵌套表单。
如果您仍然遇到问题,那么请调试 HTTP 流量。 打开网络浏览器的开发人员工具集(在 Chrome/Firebug23+/IE9+ 中按 F12)并检查网络/网络部分。 如果 HTTP 部分看起来不错,那么调试 JSF 代码。 在FileUploadRenderer#decode()
上放置一个断点并从那里前进。
在你最终让它工作后,你的下一个问题可能类似于“我如何/在哪里保存上传的文件?”。 好吧,继续在这里: 如何在 JSF 中保存上传的文件。
你也在用漂亮脸蛋吗? 然后将调度程序设置为 FORWARD:
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
我在 Primefaces 3.4 和 Netbeans 7.2 中注意到的一点:
删除函数handleFileUpload ie(事件)的Netbeans 自动填充参数,否则事件可能为空。
<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>
看起来 javax.faces.SEPARATOR_CHAR 不能等于 _
我在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 必须是这 3 个值中的 1 个,但不是全部!! 可以删除整个上下文参数部分,默认值为 auto
豆.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 公共类提交实现可序列化 {
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);
}
}
网页.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>
这里的任何建议都对我没有帮助。 所以我不得不调试primefaces,发现问题的原因是:
java.lang.IllegalStateException: No multipart config for servlet fileUpload
然后我在 web.xml 中将部分添加到我的 faces 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>
我遇到了同样的问题,因为我拥有这篇文章中描述的所有配置,但在我的情况下是因为我有两个 jquery 导入(其中一个是 primefaces 的查询),这导致了上传文件的冲突。
对于使用 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>
使用 JBoss 7.2(Undertow) 和 PrimeFaces 6.0 org.primefaces.webapp.filter.FileUploadFilter 应该从 web.xml 中删除,并且上下文参数文件上传器应该设置为原生:
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>native</param-value>
</context-param>
将p:fileUpload
h:form
解决了我的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.