考虑一个带有fileUpload组件的表单。用户使用fileUpload组件选择一些文件,然后提交表单,合理地认为所选文件与表单一起隐式提交,但事实并非如此。 Primefaces fileUpload
组件要求用户在提交之前将文件作为显式操作上载,并为此提供一个方便的“上载”按钮。但是,如果用户忽略了此操作,则提交的表单中没有文件,也没有指示已将其排除在提交之外。在某些使用情况下,文件以后可能不会附加到表单提交创建的对象上。相比之下,JSF和Omnifaces inputFile
组件以及它们所基于的HTML5 <input type="file">
会在提交时上传文件,这对我来说似乎更有用。
这是一些示例代码。首先演示:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
<f:view>
<h:form id="form" enctype="multipart/form-data" method="POST">
<p:panelGrid id="grid" columns="2" cellpadding="15">
<p:outputLabel>HTML5 input type="file"</p:outputLabel>
<input type="file" id="fileupload1" name="fileupload1" multiple="multiple" />
<p:outputLabel>Primefaces fileUpload</p:outputLabel>
<p:fileUpload id="fileupload2" fileUploadListener="#{myBean.handleFileUpload}" multiple="true" />
<p:outputLabel>JSF Input File</p:outputLabel>
<h:inputFile id="fileupload3" value="#{myBean.uploadedFile}" />
</p:panelGrid>
<p:commandButton id="submit" value="Submit" actionListener="#{myBean.submit}" process="@form" ajax="false" />
</h:form>
</f:view>
</h:body>
</html>
还有后备豆:
@ManagedBean
@SessionScoped
public class MyBean {
private Map<String, Path> uploadedFiles = new HashMap<String, Path>();
Part uploadedFile;
public void handleFileUpload(FileUploadEvent event) {
System.out.println("Uploaded file: " + event.getFile().getFileName());
}
public void submit(ActionEvent actionEvent) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
for (Part part : request.getParts()) {
if (part != null && part.getSize() > 0 && part.getSubmittedFileName() != null) {
String fileName = part.getSubmittedFileName();
String contentType = part.getContentType();
System.out.println("File in request: " + fileName + "; contentType " + contentType + "; size: " + part.getSize());
}
}
System.out.println("Primefaces uploaded Files (" + (uploadedFiles == null ? "0" : uploadedFiles.size()) + "):");
if (uploadedFiles != null) {
for (String name : uploadedFiles.keySet()) {
System.out.println(" Name: " + name + "; Path " + uploadedFiles.get(name));
}
}
System.out.println("JSF uploaded file: " + (uploadedFile == null ? "null" : uploadedFile.getSubmittedFileName() + ", size " + uploadedFile.getSize()));
}
public Part getUploadedFile() {
System.out.println("get uploaded File Part: " + (uploadedFile == null ? "none" : uploadedFile.getSubmittedFileName()));
return uploadedFile;
}
public void setUploadedFile(Part uploadedFile) {
System.out.println("set uploaded File Part: " + (uploadedFile == null ? "none" : uploadedFile.getSubmittedFileName()));
this.uploadedFile = uploadedFile;
}
}
如果在所有三个文件上传组件中选择文件后提交此表单,则Primefaces是唯一一个在提交时不上传文件的表单。当然,您可以将“ auto”设置为true,以使其在选定时上传文件,但是如果用户决定不上传文件,则无法撤消。您可以将其设置为必填,但通常情况下,用户可能不选择上载任何文件。因此,Primefaces组件似乎在这方面倒退了一步,尽管它非常易于使用并且功能更全面。
是否有Primefaces方法在提交时丢失我上载的多个文件?
答案 0 :(得分:0)
感谢@Kukeltje帮助我找到答案。
“简单”文件上传小部件,例如HTML5 <input type="file">
,JSF <h:inputFile>
和Omnifaces <o:inputFile>
,允许用户在提交时选择一个或多个要上传的文件。
一些更复杂的fileUpload小部件,例如Primefaces(带有mode="advanced"
,默认模式和multiple="true"
),允许用户在提交时间之前一键上传多个文件,但是如果用户忽略了为此,所选文件不会在提交时上传。如果设计人员希望避免可用性问题,即用户假定所选文件在提交时上载而没有上载,则PF小部件可以与mode="simple"
一起使用。以这种方式使用PF小部件的好处是美观,并且可以选择多个文件。
作为一个脚注,与原始问题无关,特别是PF小部件存在问题,在相似框架中可能还有其他相似问题。在简单模式下,如果用户选择多个文件,则小部件仅显示第一个文件。
我看到另一个问题,在用户在允许多个窗口小部件的任何一个中选择了多个文件之后,无法取消选择文件。在尝试使用JS列出所选文件后,我发现由于浏览器的安全性,我无法在JS中更改列表,请参见BalusC的答案here。我最后得到了一些简单的JS,在提交时检查了PF上载小部件是否有任何选定的文件,如果有,则阻止提交并要求用户在提交前上载文件。我认为这是最有用的解决方案。
<p:commandButton value="Submit" actionListener="#{bean.submit}" onclick="return checkAttachments();" ajax="false" />
<script>
function checkAttachments() {
var attachmentRows = $(".ui-fileupload-row");
console.log("rows " + attachmentRows.length);
if (attachmentRows.length == 0 ) {
return true;
}
PF('uploadAttachmentsWarningDialog').show();
return false;
}
</script>