Liferay.Upload 多文件上传的组件使用

Liferay.Upload Component Usage for Multi-file Upload

开发自定义 portlet 以在 Liferay 6.2 中上传多个文件。 在以下位置的文档库 Portlet 中浏览 Liferay 源代码时发现 Liferay.Upload 组件:

https://github.com/liferay/liferay-portal/blob/master/portal-web/docroot/html/portlet/document_library/upload_multiple_file_entries.jsp

我们想重用这个组件,但是找不到任何关于使用的文档。

  1. 我们如何使用 Liferay.Upload 组件?每个输入的含义和作用是什么?
  2. 我们可以在自定义 portlet 中重新使用这个 Liferay.Upload 吗?
  3. 有没有关于Liferay.Upload用法的具体文档?
  4. Web 上是否有任何已实现的 portlet 以及 Web 上可用的源代码?

以下是 Liferay 上传组件的用法摘录:

<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>

非常感谢任何指点!!

看起来这个组件重用了 all over in Liferay. I think you could reuse it as well. I've found following documentation 个初始参数。我希望它能帮助你进步。祝你好运!

我根据 Pawel 的链接进行了尝试,并在某种 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">
            &nbsp;
        </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());

  }
}

这是我使用 liferay 样式(拖放或 select 文件四边形)对 多个上传文件的实现。此代码会将文件上传到临时 liferay 文件夹 (DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) 中,然后在 ClientPortlet.java 中的方法 METHODJAVANAMEManageForm 中,您可以获取它们并根据需要使用。这和liferay多次上传文件的行为是一样的。

view.jsp

<portlet:actionURL windowState="maximized" var="NAMEUrl" name="METHODJAVANAMEManageForm">
</portlet:actionURL>

<form action="<c:out value="${NAMEUrl}"/>" method="POST" enctype="multipart/form-data">
    <liferay-util:include page="/jsp/multipleAttach.jsp" servletContext="<%=this.getServletContext()%>"/>
    <!--other <input <div <span.....-->
</form>

multipleAttach.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"%>
<%@page import="com.liferay.portal.service.TicketLocalServiceUtil"%>
<%@ page import="com.liferay.portlet.documentlibrary.model.DLFileEntryConstants" %>
<%@ page import="com.liferay.portal.kernel.util.Constants" %>
<%@page import="com.liferay.portal.service.ServiceContext"%>
<%@page import="com.liferay.portal.model.TicketConstants"%>
<%@page import="com.liferay.portal.model.User"%>
<%@page import="com.liferay.portal.model.Ticket"%>
<%@page import="com.liferay.portal.kernel.repository.model.Folder"%>
<%@page import="com.sun.mail.imap.DefaultFolder"%>
<%@page import="com.liferay.util.portlet.PortletProps"%>
<%@page import="com.liferay.portlet.documentlibrary.model.DLFolderConstants"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui"%>
<%@ taglib uri="http://liferay.com/tld/util" prefix="liferay-util"%>
<%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet"%>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme"%>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<portlet:defineObjects />
<liferay-theme:defineObjects/>

 <%
Ticket ticket = TicketLocalServiceUtil.addTicket(user.getCompanyId(), User.class.getName(), user.getUserId(), TicketConstants.TYPE_IMPERSONATE, null, null, new ServiceContext());
%>

<!--REEDME instead of<form> of view.jsp you can also use <aui:form action="<c:out value="${NAMEUrl}"/>" cssClass="lfr-export-dialog" method="post" name="fm1">-->

<div class="lfr-dynamic-uploader">
    <div class="lfr-upload-container" id="<portlet:namespace />fileUpload">
    &nbsp;
    </div>
</div>
<div id="<portlet:namespace/>fallback"></div>

<aui:script use="liferay-upload,aui-base">
    var liferayUpload = new Liferay.Upload(
        {
            boundingBox: '#<portlet:namespace />fileUpload',
            deleteFile: '<liferay-portlet:actionURL name="METHODJAVANAMEFordeleteFile" 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(DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) %>" /></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) %>',
            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: <%= DLFolderConstants.DEFAULT_PARENT_FOLDER_ID %>,
                    tempFolderName: 'com.example.portlet.ClientPortlet' <!-- this is equals of _TEMP_FOLDER_NAME_ATTACHMENT of ClientPortlet.java -->
                }
            },
            uploadFile: '<liferay-portlet:actionURL name="METHODJAVANAMEForuploadFile" 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(DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) %>" /></liferay-portlet:actionURL>&ticketKey=<%= ticket.getKey() %><liferay-ui:input-permissions-params modelName="<%= DLFileEntryConstants.getClassName() %>" />'
        }
    );
</aui:script>

ClientPortlet.java

private static final String _TEMP_FOLDER_NAME_ATTACHMENT = ClientPortlet.class.getName();

public void METHODJAVANAMEManageForm(ActionRequest actionRequest,ActionResponse actionResponse) throws IOException, PortletException 
{
    List<FileEntry> tempFileEntrys = new ArrayList<FileEntry>();
    try
    {
        ThemeDisplay themeDisplay  =(ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY);
        UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(actionRequest);
        //get selected checkbox of file to upload
        String [] selectedFile = uploadRequest.getParameterValues("selectUploadedFileCheckbox");
        if(selectedFile != null)
        {
            for(int i = 0; i < selectedFile.length; ++i)
            {
                FileEntry tmpfile = TempFileUtil.getTempFile(themeDisplay.getScopeGroupId(), themeDisplay.getUserId(), selectedFile[i], _TEMP_FOLDER_NAME_ATTACHMENT);
                if(tmpfile!=null && tmpfile.getTitle()!=null && (!tmpfile.getTitle().equals("")))
                {
                    tempFileEntrys.add(tmpfile);
                    System.out.println("file: " + tmpfile.getTitle());
                }
            }
        }

        /////upload tempFileEntrys where you needed
    }
    catch (Exception e) 
    {
        e.printStackTrace();
    }
    finally
    {
        //delete all tmp files uploaded in liferay tmp folder
        for (FileEntry tmp : tempFileEntrys) 
        {
            try 
            {
                TempFileUtil.deleteTempFile(tmp.getFileEntryId());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    actionResponse.setRenderParameter("mvcPath","/jsp/viewList.jsp");
}

public void METHODJAVANAMEForuploadFile(ActionRequest actionRequest,ActionResponse actionResponse) throws Exception 
{
    //upload file in liferay tmp folder
    UploadPortletRequest uploadPortletRequest = PortalUtil.getUploadPortletRequest(actionRequest);
    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY);
    long folderId = ParamUtil.getLong(uploadPortletRequest, "folderId");
    String sourceFileName = uploadPortletRequest.getFileName("file");
    InputStream inputStream = null;
    try 
    {
        inputStream = uploadPortletRequest.getFileAsStream("file");
        String contentType = uploadPortletRequest.getContentType("file");
        DLAppServiceUtil.addTempFileEntry(themeDisplay.getScopeGroupId(), folderId, sourceFileName,_TEMP_FOLDER_NAME_ATTACHMENT, inputStream, contentType);
        JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
        jsonObject.put("name", sourceFileName);
        jsonObject.put("title", sourceFileName);
        writeJSON(actionRequest, actionResponse, jsonObject);
    }
    catch (Exception e)
    {
        UploadException uploadException =(UploadException)actionRequest.getAttribute(WebKeys.UPLOAD_EXCEPTION);
        if ((uploadException != null) &&uploadException.isExceededSizeLimit()) 
        {
            throw new FileSizeException(uploadException.getCause());
        }
        else 
        {
            throw e;
        }
    }
    finally 
    {
        StreamUtil.cleanUp(inputStream);
    }
}       

public void METHODJAVANAMEFordeleteFile(ActionRequest actionRequest,ActionResponse actionResponse) throws IOException, PortletException 
{
    //delete file from liferay tmp folder, before uploaded
    ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY);
    long folderId = ParamUtil.getLong(actionRequest, "folderId");
    String fileName = ParamUtil.getString(actionRequest, "fileName");
    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
    try 
    {
        DLAppServiceUtil.deleteTempFileEntry(themeDisplay.getScopeGroupId(), folderId, fileName,_TEMP_FOLDER_NAME_ATTACHMENT);
        jsonObject.put("deleted", Boolean.TRUE);
    }
    catch (Exception e) 
    {
        String errorMessage = themeDisplay.translate("an-unexpected-error-occurred-while-deleting-the-file");
        jsonObject.put("deleted", Boolean.FALSE);
        jsonObject.put("errorMessage", errorMessage);
    }
    writeJSON(actionRequest, actionResponse, jsonObject);
}

Click for Result view

在尝试根据我的需要自定义此组件后,我会推荐一种不同的方式来在 Liferay 中实现文件上传。

缺少 Liferay.Upload 组件的文档以及 Liferay 文件上传 portlet 底层代码的复杂性使得自定义在 Liferay 中实现的文件上传变得困难。

我的建议如下:创建一个新的自定义 portlet 并使用 jQuery 库:jQuery 文件上传插件 Visit its website here. 这是一个写得很好的库,有不错的文档,您可以根据自己的需要调整它,因为它涵盖了您期望在文件上传器中进行的许多设置。

您的 portlet 中 jsp 视图的摘要:

<%@ 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>

如您所见,使用这个库可以非常简单地实现视图,提供文件上传器。之后像这样实施您的 portlet class 操作:

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
      //******************************************
    }
  }
}

调试paramEnum时,每次处理拖放文件上传时都会得到一个"file"参数。这是顺序机制,因此,为每个文件触发 uploadFiles 操作: