zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    基于摸板匹配的目標跟蹤算法
    spoj 2713 Can you answer these queries IV
    zoj 3633 Alice's present
    hdu 3642 Get The Treasury
    poj 1195 Mobile phones
    poj 2760 End of Windless Days
    zoj 3540 Adding New Machine
    spoj 1716 Can you answer these queries III
    spoj 1043 Can you answer these queries I
    spoj 2916 Can you answer these queries V
  • 原文地址:https://www.cnblogs.com/blackbean/p/2616889.html
Copyright © 2011-2022 走看看