SharePoint 2010 自定義Ribbon實現文檔批量下載爲Zip文件

在SharePoint 2010文檔庫中,結合單選框,在Ribbon中提供了批量處理文檔的功能,比如,批量刪除、批量簽出、批量簽入等,但是,很遺憾,沒有提供批量下載,默認的只能一個個下載,當選擇多個文檔時,下載副本就變成了灰色不可用。

在此我們將開發一個Ribbon按鈕,實現文檔(包括含有文件夾)的批量下載爲Zip壓縮包的功能。

項目資源結構圖

先上傳一張項目的資源管理結構

現在開始:打開VS2010,創建一個“空白SharePoint項目”命名DeviantPoint.DownloadZip

創建空白SharePoint項目

指定用於部署的網站

指定用於部署的網站

然後添加一個到ICSharpCode.SharpZipLib.dll(一個.NET類庫,用於處理Zip文件)的引用,然後創建一個文件夾Classes用於保存幫助類。

創建類ZipBuilder,該類用於創建zip文件,創建這個幫助類可以使得在別的地方重複使用,而不僅僅針對本項目。
通常,一個類的實例被創建後,你需要轉遞一個文件流寫入zip文件。它可以是任意類型文件流,二進制流,存儲流等等。在這個ZipBuilder類中允許你添加文件和文件夾,最終輸出到zip文件。因爲它要處理文件流,所以該類實現了IDisposable接口。
如下爲ZipBuilder類的代碼:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.IO;  
  6. using ICSharpCode.SharpZipLib.Zip;  
  7. using ICSharpCode.SharpZipLib.Core;  
  8.  
  9. namespace DeviantPoint.DownloadZip  
  10. {  
  11.     public class ZipFileBuilder : IDisposable  
  12.     {  
  13.         private bool disposed = false;  
  14.  
  15.         ZipOutputStream zipStream = null;  
  16.         protected ZipOutputStream ZipStream  
  17.         {  
  18.             get { return zipStream; }  
  19.  
  20.         }  
  21.  
  22.         ZipEntryFactory factory = null;  
  23.         private ZipEntryFactory Factory  
  24.         {  
  25.             get { return factory; }  
  26.         }  
  27.  
  28.  
  29.         public ZipFileBuilder(Stream outStream)  
  30.         {  
  31.             zipStream = new ZipOutputStream(outStream);  
  32.             zipStream.SetLevel(9); //best compression  
  33.  
  34.             factory = new ZipEntryFactory(DateTime.Now);  
  35.         }  
  36.  
  37.         public void Add(string fileName, Stream fileStream)  
  38.         {  
  39.             //create a new zip entry              
  40.             ZipEntry entry = factory.MakeFileEntry(fileName);  
  41.             entry.DateTime = DateTime.Now;  
  42.             ZipStream.PutNextEntry(entry);  
  43.  
  44.             byte[] buffer = new byte[65536];  
  45.  
  46.             int sourceBytes;  
  47.             do 
  48.             {  
  49.                 sourceBytes = fileStream.Read(buffer, 0, buffer.Length);  
  50.                 ZipStream.Write(buffer, 0, sourceBytes);  
  51.             }  
  52.             while (sourceBytes > 0);  
  53.  
  54.  
  55.         }  
  56.  
  57.         public void AddDirectory(string directoryName)  
  58.         {  
  59.             ZipEntry entry = factory.MakeDirectoryEntry(directoryName);  
  60.             ZipStream.PutNextEntry(entry);  
  61.         }  
  62.  
  63.         public void Finish()  
  64.         {  
  65.             if (!ZipStream.IsFinished)  
  66.             {  
  67.                 ZipStream.Finish();  
  68.             }  
  69.         }  
  70.  
  71.         public void Close()  
  72.         {  
  73.             Dispose(true);  
  74.             GC.SuppressFinalize(this);  
  75.         }  
  76.  
  77.         public void Dispose()  
  78.         {  
  79.             this.Close();  
  80.         }  
  81.  
  82.         protected virtual void Dispose(bool disposing)  
  83.         {  
  84.             if (!disposed)  
  85.             {  
  86.                 if (disposing)  
  87.                 {  
  88.                     if (ZipStream != null)  
  89.                         ZipStream.Dispose();  
  90.                 }  
  91.             }  
  92.  
  93.             disposed = true;  
  94.         }  
  95.     }  
  96. }  

接下來,寫一個SPExtensions.cs的類,用於向Microsoft.SharePoint對象添加一些擴展方法。這個類基本就是添加一些簡單的方法到SPListItem類和SPList類。針對SPListItem類,我添加了一個方法用於判斷是否SPListItem實例是一個文件夾,SPList類用於判斷這個列表僅僅是一個文檔。

SPExtensions的代碼如下:
SPExtensions.cs
 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Runtime.CompilerServices;  
  6. using Microsoft.SharePoint;  
  7.  
  8. namespace DeviantPoint.DownloadZip  
  9. {  
  10.     public static class SPExtensions  
  11.     {  
  12.         public static bool IsFolder(this SPListItem item)  
  13.         {  
  14.             return (item.Folder != null);  
  15.         }  
  16.  
  17.         public static bool IsDocumentLibrary(this SPList list)  
  18.         {  
  19.             return (list.BaseType == SPBaseType.DocumentLibrary);  
  20.         }  
  21.     }  
  22. }  

接下來要做的是添加一個“SharePoint映射文件夾”到項目,映射到Layouts目錄(位於SharePoint根目錄下)。在添加完SharePoint的“Layouts”映射文件夾後,我添加了一個SharePoint 2010 應該程序頁DownloadZip.aspx到DeviantPoint.DownloadZip子文件夾,該頁面負責處理來自客戶端的請求並生成對應的zip文件返回到客戶端。它的功能如同已知的在SharePoint 2010 Ribbon菜單中的“下載副本”的功能。來自客戶端的POST請求會被髮送到我的DownloadZip.aspx頁面,然後這個頁面把一些文檔進行打包壓縮到一個zip文件然後發送到客戶端瀏覽器。這個頁面需要兩個參數:

• sourceUrl –完整的文檔(文件夾,包含子文件夾),請求的來源
• itemIDs – 列表項ID ,用分號隔開的一個SPListItem ID項目集,作爲zip文件的一部分。注意:一個文件夾也有IDs如果一個文件夾被選中的話,自然其ID值也會被傳遞。
該應用程序頁的基本功能是根據傳遞過來的id檢索對應的SharePoint中的文檔項,使用ZipBuilder 類把檢索到的文檔打包成一個zip文件。如果是一個文件夾的id,則會創建文件夾(最終保存到zip文件中),並依次檢索文件夾下的所有文件

下面是DownloadZip.aspx 應用程序頁的後置代碼 :

 

  1. using System;  
  2. using System.IO;  
  3. using System.Web;  
  4. using Microsoft.SharePoint;  
  5. using Microsoft.SharePoint.WebControls;  
  6. using ICSharpCode.SharpZipLib.Zip;  
  7.  
  8. namespace DeviantPoint.DownloadZip.Layouts.DeviantPoint.DownloadZip  
  9. {  
  10.     public partial class DownloadZip : LayoutsPageBase  
  11.     {  
  12.         protected void Page_Load(object sender, EventArgs e)  
  13.         {  
  14.             string fullDocLibSourceUrl = Request.Params["sourceUrl"];  
  15.             if (string.IsNullOrEmpty(fullDocLibSourceUrl)) return;  
  16.  
  17.             string docLibUrl = fullDocLibSourceUrl.Replace(SPContext.Current.Site.Url, "");  
  18.  
  19.             SPList list = SPContext.Current.Web.GetList(docLibUrl);  
  20.             if (!list.IsDocumentLibrary()) return;  
  21.  
  22.             string pItemIds = Request.Params["itemIDs"];  
  23.             if (string.IsNullOrEmpty(pItemIds)) return;  
  24.  
  25.             SPDocumentLibrary library = (SPDocumentLibrary)list;  
  26.  
  27.             string[] sItemIds = pItemIds.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);  
  28.             int[] itemsIDs = new int[sItemIds.Length];  
  29.             for (int i = 0; i < sItemIds.Length; i++)  
  30.             {  
  31.                 itemsIDs[i] = Convert.ToInt32(sItemIds[i]);  
  32.             }  
  33.  
  34.             if (itemsIDs.Length > 0)  
  35.             {  
  36.                 using (MemoryStream ms = new MemoryStream())  
  37.                 {  
  38.                     using (ZipFileBuilder builder = new ZipFileBuilder(ms))  
  39.                     {  
  40.                         foreach (int id in itemsIDs)  
  41.                         {  
  42.                             SPListItem item = library.GetItemById(id);  
  43.                             if (item.IsFolder())  
  44.                                 AddFolder(builder, item.Folder, string.Empty);  
  45.                             else 
  46.                                 AddFile(builder, item.File, string.Empty);  
  47.                         }  
  48.  
  49.                         builder.Finish();  
  50.                         WriteStreamToResponse(ms);  
  51.                     }  
  52.                 }  
  53.             }  
  54.  
  55.         }  
  56.  
  57.         private static void AddFile(ZipFileBuilder builder, SPFile file, string folder)  
  58.         {  
  59.             using (Stream fileStream = file.OpenBinaryStream())  
  60.             {  
  61.                 builder.Add(folder + "\\" + file.Name, fileStream);  
  62.                 fileStream.Close();  
  63.             }  
  64.         }  
  65.  
  66.         private void AddFolder(ZipFileBuilder builder, SPFolder folder, string parentFolder)  
  67.         {  
  68.             string folderPath = parentFolder == string.Empty ? folder.Name : parentFolder + "\\" + folder.Name;  
  69.             builder.AddDirectory(folderPath);  
  70.  
  71.             foreach (SPFile file in folder.Files)  
  72.             {  
  73.                 AddFile(builder, file, folderPath);  
  74.             }  
  75.  
  76.             foreach (SPFolder subFolder in folder.SubFolders)  
  77.             {  
  78.                 AddFolder(builder, subFolder, folderPath);  
  79.             }  
  80.         }  
  81.  
  82.         private void WriteStreamToResponse(MemoryStream ms)  
  83.         {  
  84.             if (ms.Length > 0)  
  85.             {  
  86.                 string filename = DateTime.Now.ToFileTime().ToString() + ".zip";  
  87.                 Response.Clear();  
  88.                 Response.ClearHeaders();  
  89.                 Response.ClearContent();  
  90.                 Response.AddHeader("Content-Length", ms.Length.ToString());  
  91.                 Response.AddHeader("Content-Disposition""attachment; filename=" + filename);  
  92.                 Response.ContentType = "application/octet-stream";  
  93.  
  94.                 byte[] buffer = new byte[65536];  
  95.                 ms.Position = 0;  
  96.                 int num;  
  97.                 do 
  98.                 {  
  99.                     num = ms.Read(buffer, 0, buffer.Length);  
  100.                     Response.OutputStream.Write(buffer, 0, num);  
  101.                 }  
  102.  
  103.                 while (num > 0);  
  104.  
  105.                 Response.Flush();  
  106.             }  
  107.         }  
  108.     }  
  109. }  

在創建完應用程序頁後,我添加一個SharePoint 2010 空白元素DownloadZip到項目中,打開Elements.xml

代碼如下

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> 
  3.     <CustomAction Id="DeviantPoint.DownloadZip" Location="CommandUI.Ribbon"> 
  4.         <CommandUIExtension> 
  5.             <CommandUIDefinitions> 
  6.                 <CommandUIDefinition Location="Ribbon.Documents.Copies.Controls._children"> 
  7.                     <Button Id="Ribbon.Documents.Copies.DownloadZip" 
  8.                             Command="DownloadZip" 
  9.                             Sequence="15" 
  10.                             Image16by16="/_layouts/images/DeviantPoint.DownloadZip/zip_16x16.png" 
  11.                             Image32by32="/_layouts/images/DeviantPoint.DownloadZip/zip_32x32.png" 
  12.                             Description="Download zip" LabelText="Download as Zip" 
  13.                             TemplateAlias="o1"/> 
  14.                 </CommandUIDefinition> 
  15.             </CommandUIDefinitions> 
  16.             <CommandUIHandlers> 
  17.                 <CommandUIHandler 
  18.                   Command="DownloadZip" 
  19.                   CommandAction="javascript:downloadZip();" 
  20.                   EnabledScript="javascript:enable();"/> 
  21.             </CommandUIHandlers> 
  22.         </CommandUIExtension> 
  23.     </CustomAction> 
  24.     <CustomAction Id="Ribbon.Library.Actions.Scripts" 
  25.                   Location="ScriptLink" 
  26.                   ScriptSrc="/_layouts/DeviantPoint.DownloadZip/CustomActions.js" /> 
  27. </Elements> 

對此CommandUIDefinition, 我設置 Location attribute 爲"Ribbon.Documents.Copies.Controls._children”. 我還希望它能夠顯示在“下載副本”功能的右邊,因此需要設置按鈕元素序列號屬性,設置爲15(這個“下載副本按鈕的序列號爲10,發送到按鈕的序列號爲20,自然我需要設置它的序列號爲它們之間),想要知道每個功能按鈕的序列號你可能查看C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\GLOBAL\XML\CMDUI.xml 文件。我同時也指定了功能按鈕的圖像(創建一個SharePoint的“Images”映射文件夾),同時指定TemplateAlias爲“o1”以便我的圖標顯示的大些,如同“下載副本”的一樣。我也定義按鈕的command處理事件在Elements.xml文件中通過添加一個CommandUIHandler元素。這CommandAction 屬性用於指定按鈕被期望的動作,EnabledScript屬性用於決定是否按鈕功能被啓用。這兩個屬性值都指向一個javascript函數(放在一個單獨的文件中,稍後討論)因爲我使用了一個單獨的javascript文件,我還必須在Elements文件中添加另一個CustomAction元素,用以指名我的javascript文件的位置。

最後,創建CustomActions.js文件,這個文件用於定義ribbon按鈕的功能/行爲。enable()函數用於決定按鈕是否可用。如果至少有一個文檔項被選中的話,那麼我的按鈕就是可用的。 downloadZip() 函數用於開始下載過程

如下爲CustomActions.js 的源碼:

  1. function enable() {  
  2.     var items = SP.ListOperation.Selection.getSelectedItems();  
  3.     var itemCount = CountDictionary(items);  
  4.     return (itemCount > 0);  
  5.  
  6. }  
  7.  
  8. function downloadZip() {  
  9.  
  10.     var context = SP.ClientContext.get_current();  
  11.     this.site = context.get_site();  
  12.     this.web = context.get_web();  
  13.     context.load(this.site);  
  14.     context.load(this.web);  
  15.     context.executeQueryAsync(  
  16.         Function.createDelegate(thisthis.onQuerySucceeded),  
  17.         Function.createDelegate(thisthis.onQueryFailed)  
  18.     );  
  19. }  
  20.  
  21. function onQuerySucceeded() {  
  22.  
  23.     var items = SP.ListOperation.Selection.getSelectedItems();  
  24.     var itemCount = CountDictionary(items);  
  25.  
  26.     if (itemCount == 0) return;  
  27.  
  28.     var ids = "";  
  29.     for (var i = 0; i < itemCount; i++) {  
  30.         ids += items[i].id + ";";  
  31.     }  
  32.  
  33.     //send a request to the zip aspx page.  
  34.     var form = document.createElement("form");  
  35.     form.setAttribute("method""post");  
  36.     form.setAttribute("action"this.site.get_url() + this.web.get_serverRelativeUrl() + "/_layouts/deviantpoint.downloadzip/downloadzip.aspx");  
  37.  
  38.     var hfSourceUrl = document.createElement("input");  
  39.     hfSourceUrl.setAttribute("type""hidden");  
  40.     hfSourceUrl.setAttribute("name""sourceUrl");  
  41.     hfSourceUrl.setAttribute("value", location.href);  
  42.     form.appendChild(hfSourceUrl);  
  43.  
  44.     var hfItemIds = document.createElement("input")  
  45.     hfItemIds.setAttribute("type""hidden");  
  46.     hfItemIds.setAttribute("name""itemIDs");  
  47.     hfItemIds.setAttribute("value", ids);  
  48.     form.appendChild(hfItemIds);  
  49.  
  50.     document.body.appendChild(form);  
  51.     form.submit();  
  52. }  
  53.  
  54. function onQueryFailed(sender, args) {  
  55.     this.statusID = SP.UI.Status.addStatus("Download as Zip:",  
  56.         "Downloading Failed: " + args.get_message() + " <a href='#' onclick='javascript:closeStatus();return false;'>Close</a>."true);  
  57.     SP.UI.Status.setStatusPriColor(this.statusID, "red");  
  58. }  
  59.  
  60. function closeStatus() {  
  61.     SP.UI.Status.removeStatus(this.statusID);  

到此結束,生成並部署,即可實現文檔(文件夾)的批量下載爲壓縮包。

批量下載爲壓縮包

如果你出現“找不到文件的錯誤”,請看下一篇文章,這是因爲沒有把ICSharpCode.SharpZipLib.dll註冊到GAC的原因。

本文翻譯於:http://www.deviantpoint.com/post/2010/05/08/SharePoint-2010-Download-as-Zip-File-Custom-Ribbon-Action.aspx

本人新手,請大家多多關照,也歡迎與我進行技術溝通。QQ:906753030

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章