Developing a custom portlet to upload multiple files in Liferay 6.2. Found the Liferay.Upload component while going through Liferay Source Code in the Document Library Portlet at the following location:
https://github.com/liferay/liferay-portal/blob/master/portal-web/docroot/html/portlet/document_library/upload_multiple_file_entries.jsp
We want to reuse this component, but unable to find any documentation regarding the usage.
Liferay.Upload
component? What do each of the inputs mean & do?Liferay.Upload
in our custom portlet?Liferay.Upload
?Given below is the extract of the usage of the Liferay Upload component:
<aui:script use="liferay-upload">
new Liferay.Upload(
{
boundingBox: '#<portlet:namespace />fileUpload',
deleteFile: '<liferay-portlet:actionURL doAsUserId="<%= user.getUserId() %>"><portlet:param name="struts_action" value="/document_library/edit_file_entry" /><portlet:param name="<%= Constants.CMD %>" value="<%= Constants.DELETE_TEMP %>" /><portlet:param name="folderId" value="<%= String.valueOf(folderId) %>" /></liferay-portlet:actionURL>&ticketKey=<%= ticket.getKey() %><liferay-ui:input-permissions-params modelName="<%= DLFileEntryConstants.getClassName() %>" />',
fileDescription: '<%= StringUtil.merge(PrefsPropsUtil.getStringArray(PropsKeys.DL_FILE_EXTENSIONS, StringPool.COMMA)) %>',
maxFileSize: '<%= PrefsPropsUtil.getLong(PropsKeys.DL_FILE_MAX_SIZE) %> B',
metadataContainer: '#<portlet:namespace />commonFileMetadataContainer',
metadataExplanationContainer: '#<portlet:namespace />metadataExplanationContainer',
namespace: '<portlet:namespace />',
tempFileURL: {
method: Liferay.Service.bind('/dlapp/get-temp-file-entry-names'),
params: {
groupId: <%= scopeGroupId %>,
folderId: <%= folderId %>,
tempFolderName: 'com.liferay.portlet.documentlibrary.action.EditFileEntryAction'
}
},
tempRandomSuffix: '<%= EditFileEntryAction.TEMP_RANDOM_SUFFIX %>',
uploadFile: '<liferay-portlet:actionURL doAsUserId="<%= user.getUserId() %>"><portlet:param name="struts_action" value="/document_library/edit_file_entry" /><portlet:param name="<%= Constants.CMD %>" value="<%= Constants.ADD_TEMP %>" /><portlet:param name="folderId" value="<%= String.valueOf(folderId) %>" /></liferay-portlet:actionURL>&ticketKey=<%= ticket.getKey() %><liferay-ui:input-permissions-params modelName="<%= DLFileEntryConstants.getClassName() %>" />'
}
);
</aui:script>
Any pointers are highly appreciated!!
I gave it a shot based on Pawel's links and succeeded in a sort-of POC.
view.jsp
<%@page import="com.liferay.portal.kernel.util.ParamUtil"%>
<%@page import="com.liferay.portal.kernel.portlet.LiferayWindowState"%>
<%@page import="com.liferay.portal.kernel.util.StringPool"%>
<%@page import="com.liferay.portal.kernel.util.PropsKeys"%>
<%@page import="com.liferay.portal.kernel.util.PrefsPropsUtil"%>
<%@page import="com.liferay.portal.kernel.util.StringUtil"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui"%>
<portlet:defineObjects />
This is the <b>Liferay File Upload</b> portlet in View mode.
<portlet:actionURL name="uploadFile" var="uploadFileURL" >
<portlet:param name="jspPage" value="/html/singefileuploadaction/view.jsp" />
</portlet:actionURL>
<portlet:resourceURL var="importPortletURL" id="uploadSubmit">
<portlet:param name="jspPage" value="/html/singefileuploadaction/view.jsp" />
</portlet:resourceURL>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<aui:form action="<%= importPortletURL %>" cssClass="lfr-export-dialog" method="post" name="fm1">
<div class="lfr-dynamic-uploader">
<div class="lfr-upload-container" id="<portlet:namespace />fileUpload">
</div>
</div>
<div id="<portlet:namespace/>fallback"></div>
<aui:button-row>
<aui:button cssClass='hide' name="continueButton" type="submit" value="Continue" />
</aui:button-row>
<aui:script use="liferay-upload,aui-base">
var liferayUpload = new Liferay.Upload({
allowedFileTypes: '<%= StringUtil.merge(PrefsPropsUtil.getStringArray(PropsKeys.DL_FILE_EXTENSIONS, StringPool.COMMA)) %>',
container: '#<portlet:namespace />fileUpload',
maxFileSize: <%=Long.parseLong(PrefsPropsUtil.getString(PropsKeys.DL_FILE_MAX_SIZE)) %> / 1024,
namespace:'<portlet:namespace />',
uploadFile: '<%=uploadFileURL.toString()%>',
tempFileRemoved: function(){console.log('Temp File Removed');},
'strings.dropFilesText': 'Drop Files Here to Upload.',
'strings.dropFileText': 'Drop File Here to Upload.',
'strings.selectFileText': 'Select File to Upload.',
'strings.selectFilesText': 'Select Files to Upload.',
'strings.fileCannotBeSavedText': 'File cannot be saved.',
'strings.pendingFileText': 'This file was previously uploaded but not actually saved',
'strings.uploadsCompleteText': 'Upload is complete. Please save.',
multipleFiles: false
});
<!-- ASHOK: !IMPORTANT-DO NOT REMOVE-This code is to re-position the Upload Component HTML code which is placed on top of the page by default: Might be a BUG?? -->
$( document ).ready(function() {
$('.component.liferayupload').appendTo("#<portlet:namespace />fileUpload");
});
var continueButton = A.one('#<portlet:namespace />continueButton');
function toggleContinueButton() {
var uploadedFiles = liferayUpload._fileListContent.all('.upload-file.upload-complete');
if (uploadedFiles.size() == 1) {
console.log('One file Upload');
console.log(uploadedFiles);
continueButton.show();
}
else {
console.log(uploadedFiles);
continueButton.hide();
}
}
<!-- Ashok: Upload Component Events BEGIN-->
<!-- Ashok: Fired when File Upload STARTS-->
liferayUpload._uploader.on(
'fileuploadstart',
function(event) {
console.log('File Upload Start');
}
);
<!-- Ashok: Fired when File Upload is COMPLETE-->
Liferay.on(
'uploadcomplete',
function(event) {
console.log('File Upload Complete');
}
);
<!-- Ashok: Fired when All Uploads are COMPLETE-->
liferayUpload._uploader.on(
'alluploadscomplete',
function(event) {
console.log('All Uploads Complete');
toggleContinueButton();
}
);
<!-- Ashok: Fired when Temp file is REMOVED-->
Liferay.on(
'tempFileRemoved',
function(event) {
console.log('Temp File Removed');
toggleContinueButton();
}
);
<!-- Ashok: Upload Component Events END-->
$('#<portlet:namespace />continueButton').on(
'click',
function(event) {
event.preventDefault();
$('#<portlet:namespace />fm1').ajaxSubmit(
{
success: function(responseData) {
<%-- $('#<portlet:namespace />exportImportOptions').html(responseData); --%>
}
}
);
}
);
</aui:script>
</aui:form>
SingeFileUploadAction.java
package com.ashok.liferay.upload;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import com.liferay.portal.kernel.upload.UploadPortletRequest;
import com.liferay.portal.util.PortalUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;
/**
* Portlet implementation class SingeFileUploadAction
*/
public class SingeFileUploadAction extends MVCPortlet {
public void uploadFile(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException {
System.out.println("In SingeFileUploadAction");
UploadPortletRequest uploadRequest=PortalUtil.getUploadPortletRequest(actionRequest);
File file =uploadRequest.getFile("file");
String fileName = uploadRequest.getFileName("file");
System.out.println("FileName:"+fileName);
//Mike Test
Map<String, String[]> reqMap = actionRequest.getParameterMap();
System.out.println("Printing all actionRequest Params");
for (Map.Entry<String, String[]> entry : reqMap.entrySet())
{
System.out.println(entry.getKey() + "/" + Arrays.toString(entry.getValue()));
}
System.out.println("----------\nPrinting all uploadRequest Params");
Map<String, String[]> upReqMap =uploadRequest.getParameterMap();
for (Map.Entry<String, String[]> entry : upReqMap.entrySet())
{
System.out.println(entry.getKey() + "/" + Arrays.toString(entry.getValue()));
}
System.out.println(file.getName());
}
public void uploadSubmit(ResourceRequest resourceRequest,
ResourceResponse resourceResponse) {
System.out.println("In uploadSubmit");
UploadPortletRequest uploadRequest=PortalUtil.getUploadPortletRequest(resourceRequest);
// File file =uploadRequest.getFile("file");
// System.out.println(file.getName());
}
}
After trying to customize this component for my needs, I would recommend a different way to implement file uploading in Liferay.
The lack of documentation of the Liferay.Upload Component plus the complexity of the underlaying code of the Liferay File Upload portlet makes it a difficult path to customize the file uploading implemented in Liferay.
My recommendation is the following: create a new custom portlet and use the jQuery library: jQuery File UPload plugin. Visit its website here. It is a well written library with decent documentation, you can adapt it to your needs since it covers a lot of the settings you would expect in a file uploader.
A summary of how the jsp view in your portlet would be:
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui"%>
<portlet:defineObjects />
File Bulk Uploader
<portlet:actionURL var="uploadFileURL" name="uploadFiles"/>
<script>
$(document).ready(function(){
$("#multipleupload").uploadFile({
url:"<%= uploadFileURL.toString() %>",
multiple:true,
dragDrop:true,
sequential:true,
sequentialCount:1
});
});
</script>
<div id="multipleupload">Upload</div>
As you can see, using this library makes a really simple implementation of the view, providing a file uploader. Implement afterwards your portlet class action like this:
public void uploadFiles(ActionRequest request, ActionResponse response) throws PortletException, IOException, SystemException, PortalException{
UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(request);
Enumeration<?> paramEnum = uploadRequest.getParameterNames();
File tempFile;
Map<String, File> fileMap = new LinkedHashMap<String, File>();
while (paramEnum.hasMoreElements()){
String parameter = (String) paramEnum.nextElement();
if (parameter.startsWith("file")){
tempFile = uploadRequest.getFile(parameter);
//******************************************
//do what you need with the file here
//******************************************
}
}
}
When debugging paramEnum, it gets a "file" parameter each time a dragged and dropped file is processed for upload. This is the sequential mechanism and so, the uploadFiles action is triggered for each file:
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