I want to upload files larger than 2 GB with Java EE with the use of primefaces. In general that it's not that big deal, but I have a little problem. The usually way with PrimeFaces is to upload a file, have that UploadedFile-Object, obtain the InputStream from that and then write it to disk.
But writing to disk large files is a time intensive task. Instead I would like to find the uploaded file in the file system and then move it to the folder, where I store all the files, because moving files is not wasting time.
So, according to this question here I figured out to set PrimeFaces-Tmp-folder and the size-limit, when files will put there. Now every uploaded file just goes directly into that folder. The point is, that I now have a file on disk, while the user is uploading - and not creating it afterwards.
So far, so good. I could identify the file and just move it (although it has a strange name). But pointing to Primefaces Userguide (Page 187), this Tmp-Folder is just used internally. And I even would steal the contents of the UploadedFile-Object from Primefaces. Seems not to be a clean solution to me.
Any hints how to achieve this ?
I also saw this question. Could also be my title, but it's not what I am looking for.
EDIT:
Because of the comment, some code. First I am collecting the UploadFile-Objects in the fileUploadListener:
public void handleFileUpload(FileUploadEvent event) throws IOException {
FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
getUploadedFilesDTO().add(new UploadedFileDTO(event.getFile(), uploadedFilesCounter));
uploadedFilesCounter++;
}
Second in the EJB I am calling copyFile for every UploadedFile-Object:
private void copyFile(UploadedFile uploadedFile, String randomFilename) throws IOException {
InputStream originalFile = uploadedFile.getInputstream();
OutputStream fileOutput = null;
try {
fileOutput = new FileOutputStream("/pvtfiles/" + randomFilename);
IOUtils.copy(originalFile, fileOutput);
} finally {
IOUtils.closeQuietly(fileOutput);
IOUtils.closeQuietly(originalFile);
}
}
I was able to do this by writing a custom filter, as AZ_ suggested, and adding the following:
FileItem fileItem = multipartRequest.getFileItem("form:fileUpload");
File file = new File(uploadDir + "/" + fileItem.getName());
fileItem.write(file);
The trick is to usethe MultipartRequest
object to get the a FileItem
object. FileItem
's
write
method can be used to save the file in a different location or using a different name. According to the documentation, some implementations may still do this with a copy, but what I am using (Apache Commons 1.3) seems to do this with a rename/move as desired. Note that the string used in getFileItem
to find the FileItem
is the ID attribute from the <p:fileUpload>
tag.
More Code:
Modified portion of web.xml
:
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>some.package.CustomFileUploadFilter</filter-class>
</filter>
Sample jsf:
<h:form id="form">
<h:panelGrid columns="1" class="blockleft">
<p:fileUpload
id="fileUpload"
auto="true" />
</h:panelGrid>
</h:form>
Sample custom filter class:
package some.package;
import java.io.File;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.primefaces.webapp.MultipartRequest;
import org.primefaces.webapp.filter.FileUploadFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CustomFileUploadFilter extends FileUploadFilter {
private static final Logger LOG = LoggerFactory.getLogger(CustomFileUploadFilter.class);
private String thresholdSize;
private String uploadDir;
private final static String THRESHOLD_SIZE_PARAM = "thresholdSize";
private final static String UPLOAD_DIRECTORY_PARAM = "uploadDirectory";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
thresholdSize = filterConfig.getInitParameter(THRESHOLD_SIZE_PARAM);
uploadDir = filterConfig.getInitParameter(UPLOAD_DIRECTORY_PARAM);
LOG.info("CatalogFileUploadFilter initiated successfully");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
boolean isMultipart = ServletFileUpload.isMultipartContent(httpServletRequest);
if (isMultipart) {
LOG.info("Parsing file upload request");
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
if (thresholdSize != null){
diskFileItemFactory.setSizeThreshold(Integer.valueOf(thresholdSize).intValue());
}
if (uploadDir != null){
diskFileItemFactory.setRepository(new File(uploadDir));
}
ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
MultipartRequest multipartRequest = new MultipartRequest(httpServletRequest, servletFileUpload);
try {
FileItem fileItem = multipartRequest.getFileItem("form:fileUpload");
File file = new File("path/to/location/" + fileItem.getName());
fileItem.write(file);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
LOG.info("File upload request parsed successfully, continuing with filter chain with a wrapped multipart request");
filterChain.doFilter(multipartRequest, response);
} else {
filterChain.doFilter(request, response);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With