我正在尝试使用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版本。
以下要求适用于所有PrimeFaces版本:
enctype
的<h:form>
属性需要设置为multipart/form-data
。如果不存在,则ajax上传可能正常工作,但一般的浏览器行为未指定,并且取决于表单组成和webbrowser make / version。只需始终指明它是安全的。mode="advanced"
(即ajax上传,这是默认设置)时,请确保在(主)模板中有<h:head>
。这将确保正确包含必要的JavaScript文件。这不是mode="simple"
(非ajax上传)所必需的,但这会破坏所有其他PrimeFaces组件的外观和功能,所以你不想错过它。mode="simple"
(即非ajax上传)时,必须在ajax="false"
的任何PrimeFaces命令按钮/链接上禁用ajax,并且必须使用<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>
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!
}
请注意,在auto
中忽略了与ajax相关的属性,如allowTypes
,update
,onstart
,oncomplete
,mode="simple"
等。因此,在这种情况下指定它们是不必要的。
另请注意,您应该立即在上述方法中读取文件内容,而不是在稍后的HTTP请求调用的不同bean方法中。这是因为上载的文件内容是请求范围的,因此在稍后/不同的HTTP请求中不可用。在稍后的请求中读取它的任何尝试都很可能最终在临时文件上使用java.io.FileNotFoundException
。
如果您使用的是JSF 2.2,并且您的faces-config.xml
也被声明为符合JSF 2.2版本,则不需要任何其他配置。您根本不需要PrimeFaces文件上传过滤器。如果您不清楚如何根据所使用的目标服务器正确安装和配置JSF,请前往How to properly install and configure JSF libraries via Maven?和"Installing JSF" section of our JSF wiki page。
如果你还没有使用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>
<servlet-name>
的facesServlet
值必须与<servlet>
在同一个javax.faces.webapp.FacesServlet
中的web.xml
条目中的值完全匹配。所以,如果它是Faces Servlet
,然后你需要相应地编辑它以匹配。
与PrimeFaces 5.x相同的故事同样适用于4.x.
通过UploadedFile#getContents()
获取上传的文件内容只有潜在的问题。当使用本机API而不是Apache Commons FileUpload时,这将返回null
。你需要使用UploadedFile#getInputStream()
代替。另见How to insert uploaded image from p:fileUpload as BLOB in MySQL?
本机API的另一个潜在问题将表现在上传组件出现在一个表单上,在该表单中触发了不处理上传组件的不同“常规”ajax请求。另见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部分。
此版本不支持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配置无关的另一个可能的原因:
Filter
,它在PrimeFaces文件上传过滤器之前运行并且已经消耗了请求正文。叫getParameter()
,getParameterMap()
,getReader()
,etcetera。请求正文只能解析一次。在文件上载过滤器完成其工作之前调用其中一个方法时,文件上载过滤器将获得一个空的请求主体。
要解决此问题,您需要将文件上传过滤器的<filter-mapping>
放在web.xml
中的另一个过滤器之前。如果请求不是multipart/form-data
请求,那么文件上传过滤器将继续,就好像什么都没发生一样。如果您使用由于使用注释而自动添加的过滤器(例如,PrettyFaces),则可能需要通过web.xml添加显式排序。见How to define servlet filter order of execution using annotations in WARFilter
,它在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流量。打开webbrowser的开发人员工具集(在Chrome / Firebug23 + / IE9 +中按F12)并检查网络/网络部分。如果HTTP部分看起来很好,那么调试JSF代码。在FileUploadRenderer#decode()
上设一个断点并从那里前进。
在你最终使用它之后,你的下一个问题应该是“我如何/在哪里保存上传的文件?”。好吧,继续这里:How to save uploaded file in JSF。
你也在使用prettyfaces?然后将调度程序设置为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的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>
看起来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>
参数值必须是这3个值中的1个,但不是全部!可以删除整个context-param部分,默认为auto
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 public class 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);
}
}
网嗯
<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中将section添加到了我的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>
我有同样的问题,因为我有这篇文章中描述的所有配置,但在我的情况下是因为我有两个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>