Consider a form with a fileUpload component. The user selects some files using the fileUpload component, then submits the form, reasonably thinking that the selected files are implicitly submitted with the form but they are not. The Primefaces fileUpload
component requires the user to upload the files as an explicit action before submit and provide a convenient "Upload" button for this purpose. However, if the user neglects to do this, the form is submitted with no file(s) and no indication that they were excluded from the submit. In some use cases, the files may not later be attached to the object created by the form submit. By contrast the JSF and Omnifaces inputFile
components and the HTML5 <input type="file">
on which they are based upload the files on submit which seems more usable to me.
Here is some example code. First the presentation:
<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>
And the backing bean:
@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;
}
}
If you submit this form after selecting files in all three file upload components, the Primefaces one is the only one that does not upload the files on submit. Granted, you can set "auto" to true to cause it to upload the files on selection, but then there is no way to back out if the user decides not to upload a file. You can set it to required, but in the general case the user may not elect to upload any file. So it seems that the Primefaces component is a step backward in this regard, although it is very easy to use and way more full featured.
Is there a Primefaces way to upload multiple files at submit time that I am missing?