項目上有時候會需要使用自定義的組件來上傳需要的文件,通過Docusment借助Salesforce標准的組件來完成這個演示
先看運行效果:

VF Page 代碼
<apex:page controller="FileUploadController" showHeader="false" sidebar="false" > <apex:form > <apex:pagemessages /> <apex:pageBlock > <apex:pageBlockSection columns="4"> <apex:inputFile value="{!csvFileBody}" filename="{!csvAsString}"/> <apex:commandButton value="Import file" action="{!importFile}"/> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page>
APEX 代碼
public class FileUploadController { public Blob csvFileBody{get;set;} public String csvAsString{get;set;} public String oppId{get;set;} public FileUploadController(){ oppId = ApexPages.currentPage().getParameters().get('oppId'); System.debug(oppId); } public void importFile(){ // Insert file ContentVersion contentVersion_1 = new ContentVersion(); contentVersion_1.Title = csvAsString; contentVersion_1.PathOnClient = csvAsString; contentVersion_1.VersionData = csvFileBody; insert contentVersion_1; System.debug('file id:' + contentVersion_1.Id); // query file List<ContentVersion> list_version = [SELECT contentdocumentid,ownerid FROM ContentVersion WHERE id =: contentVersion_1.Id]; ContentDocumentLink link = new ContentDocumentLink(); link.ContentDocumentId = list_version[0].contentdocumentid; link.LinkedEntityId = oppId; link.ShareType = 'V'; // save file in the record insert link; } }
訪問VF頁面時傳入Opportunity的Id,點擊上傳文件,Import后傳入的文件會出現在對應的Opportunity下面。
調用Salesforce的標准組件來實現,唯一需要注意的是對Document的DML操作, 相對Attachment來說要更復雜一些,不過這樣實現的頁面有一個很嚴重的問題,那就是組件上傳的文件大小,受VisualPage本身135KB大小的限制(現在似乎更新到170KB), 進而導致上傳的文件必須小於170KB, 這樣的實現是不夠的
那么我們迭代一個新的版本,優化一下頁面元素,同時將文件上傳的大小限制擴大
迭代后運行效果如下:

VF Page代碼:
<apex:page controller="FileUploadController" sidebar="false" showHeader="false" standardStylesheets="false"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <apex:stylesheet value="{!URLFOR($Resource.bootstrap3, '/css/bootstrap.css')}"/> <apex:includeScript value="{!URLFOR($Resource.jqueryui,'/external/jquery/jquery.js')}" /> <apex:includeScript value="{!URLFOR($Resource.jqueryui, '/jquery-ui.js')}" /> <apex:includeScript value="{!URLFOR($Resource.bootstrap3, '/js/bootstrap.js')}"/> <style type="text/css"> #drop { border: 2px dashed #bbb; border-radius: 5px; text-align: center; font: 15px bold,"Vollkorn"; color: gray; background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ECECEC),to(#FEE0C6)); position: fixed; bottom: 0; left: 0; height: 60px; line-height: 60px; width: 100%; z-index: 4; } </style> <body> <apex:form > <div class="container" style="padding-top: 15px; margin-bottom: 50px;"> <div class="row"> <div class="panel panel-info"> <div class="panel-heading" id="output">Tip: please download the latest template </div> <div class="panel-body"> <div class="row" id="buttonGroupArea"> <div class="col-md-7"> <apex:outputPanel > <a class="btn btn-info" target="_blank" href="模板下載鏈接">Download Template</a> </apex:outputPanel> </div> <div class="col-md-2"> <div class="btn-group pull-right " role="group" aria-label="..."></div> <button type="button" id="upload" class="btn btn-info" onclick="saveAttachment()">Import file</button> </div> </div> </div> </div> </div> </div> </div> <!--Hide input to handle click uploads--> <div style="display:none;"> <input type="file" id="fileInput" value="" filename="fileInput"/> </div> <div id="drop"> Click or drag files here to upload </div> </apex:form> </body> <script type="text/javascript"> function saveAttachment() { var testFiles = document.getElementById('fileInput').files; filesReader(testFiles); } /** * Click the upload file button and trigger when a file is selected * * */ function changeFileValue(e){ // get file elements var fileInput = document.getElementById('fileInput') var testFiles = fileInput.files; var testFile = testFiles[0]; if(testFile != undefined){ var file_Name = testFile.name; var dropValue = document.getElementById('drop'); dropValue.innerText = 'Selected files:' + file_Name; } } /***** * * Triggered when placing a file into a specified area */ function handleDrop(e) { e.stopPropagation(); e.preventDefault(); var files = e.dataTransfer.files; filesReader(files); } function filesReader(testFiles){ var maxFileSize = 4350000; //Maximum number of file bytes after Base64 encoding var file_Body; //file body var file_Name; //file Name var testFile = testFiles[0]; if(testFile != undefined) { if(testFile.size <= maxFileSize) { file_Name = testFile.name; var dropValue = document.getElementById('drop'); dropValue.innerText = 'Please wait,' + file_Name + ' is uploading ...'; var fileReader = new FileReader(); fileReader.onloadend = function(e) { file_Body = window.btoa(this.result); //Base 64 encode the file Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.FileUplo adController.testAddAttachment}',file_Name,file_Body,'{!oppId}', function(result,event) { dropValue.innerText = 'Click or drag files here to upload'; alert(result); }); } fileReader.onerror = function(e) { alert("Upload failed, please try again"); } fileReader.onabort = function(e) { alert("Upload failed, please try again"); } fileReader.readAsBinaryString(testFile); } else { alert("Base64 encoding allows up to 4.3M files"); } } else { alert("Please select a file to upload first."); } } function handleDragover(e) { e.stopPropagation(); e.preventDefault(); e.dataTransfer.dropEffect = 'copy'; } // Click to pop up file selection window function showFileBox(){ var active = document.getElementById("fileInput"); var mouseEvent = document.createEvent("MouseEvents"); mouseEvent.initEvent("click", true, true); active.dispatchEvent(mouseEvent); } // Add drag event listener var drop = document.getElementById('drop'); if (drop.addEventListener) { drop.addEventListener('dragenter', handleDragover, false); drop.addEventListener('dragover', handleDragover, false); drop.addEventListener('drop', handleDrop, false); //Add click file event listener drop.addEventListener('click',showFileBox,false); } // Listen for the Change event of InputFile var fileInputDom = document.getElementById('fileInput'); if(fileInputDom.addEventListener){ fileInputDom.addEventListener('change',changeFileValue,false); } </script> </head> </apex:page>
Apex Code 代碼:
public class FileUploadController { public Blob csvFileBody{get;set;} public String csvAsString{get;set;} public String oppId{get;set;} public FileUploadController(){ oppId = ApexPages.currentPage().getParameters().get('oppId'); System.debug(oppId); } @RemoteAction public static String testAddAttachment(String attachmentName,String attachmentBody,String parentId) { String operateResult; ContentVersion contentVersion_1 = new ContentVersion(); contentVersion_1.Title = attachmentName; contentVersion_1.PathOnClient = attachmentName; contentVersion_1.VersionData = EncodingUtil.base64Decode(attachmentBody); try { insert contentVersion_1; List<ContentVersion> list_version = [SELECT contentdocumentid,ownerid FROM ContentVersion WHERE id =: contentVersion_1.Id]; ContentDocumentLink link = new ContentDocumentLink(); link.ContentDocumentId = list_version[0].contentdocumentid; link.LinkedEntityId = parentId; link.ShareType = 'V'; // save file in the record insert link; operateResult = 'import Successfully'; } catch (Exception e){ operateResult = 'import Failed'; } return operateResult; } }
比較初始版本,這個版本的UI進行了簡單的調整,在新增了拖拽文件上傳的功能的同時,將文件上傳的大小擴增至4.3M(Base64編碼大小限制),通過異步傳遞數據,繞過了VisualForce Page大小的限制
Tips: 新版本需要引入Jquery和Bootstrap3的資源庫來實現
文件的上傳真要實現起來很比較這個更加復雜,比如將上傳文件的大小進一步擴大該如何實現,比如如何同時上傳多個文件,將文件上傳的狀態進度條分別進行顯示,需求很多,只能略做拋磚引玉,希望有所幫助