设为首页 收藏本站
查看: 962|回复: 0

[经验分享] SharePoint 2010 自定义Ribbon实现文档批量下载为Zip文件

[复制链接]

尚未签到

发表于 2019-2-4 07:58:58 | 显示全部楼层 |阅读模式
  在SharePoint 2010文档库中,结合单选框,在Ribbon中提供了批量处理文档的功能,比如,批量删除、批量签出、批量签入等,但是,很遗憾,没有提供批量下载,默认的只能一个个下载,当选择多个文档时,下载副本就变成了灰色不可用。
  在此我们将开发一个Ribbon按钮,实现文档(包括含有文件夹)的批量下载为Zip压缩包的功能。

  先上传一张项目的资源管理结构
  现在开始:打开VS2010,创建一个“空白SharePoint项目”命名DeviantPoint.DownloadZip

  指定用于部署的网站

  然后添加一个到ICSharpCode.SharpZipLib.dll(一个.NET类库,用于处理Zip文件)的引用,然后创建一个文件夹Classes用于保存帮助类。
  创建类ZipBuilder,该类用于创建zip文件,创建这个帮助类可以使得在别的地方重复使用,而不仅仅针对本项目。
  
通常,一个类的实例被创建后,你需要转递一个文件流写入zip文件。它可以是任意类型文件流,二进制流,存储流等等。在这个ZipBuilder类中允许你添加文件和文件夹,最终输出到zip文件。因为它要处理文件流,所以该类实现了IDisposable接口。
  
如下为ZipBuilder类的代码:
  


  • using System;
  • using System.Collections.Generic;
  • using System.Linq;
  • using System.Text;
  • using System.IO;
  • using ICSharpCode.SharpZipLib.Zip;
  • using ICSharpCode.SharpZipLib.Core;

  • namespace DeviantPoint.DownloadZip
  • {
  •     public class ZipFileBuilder : IDisposable
  •     {
  •         private bool disposed = false;

  •         ZipOutputStream zipStream = null;
  •         protected ZipOutputStream ZipStream
  •         {
  •             get { return zipStream; }

  •         }

  •         ZipEntryFactory factory = null;
  •         private ZipEntryFactory Factory
  •         {
  •             get { return factory; }
  •         }


  •         public ZipFileBuilder(Stream outStream)
  •         {
  •             zipStream = new ZipOutputStream(outStream);
  •             zipStream.SetLevel(9); //best compression

  •             factory = new ZipEntryFactory(DateTime.Now);
  •         }

  •         public void Add(string fileName, Stream fileStream)
  •         {
  •             //create a new zip entry
  •             ZipEntry entry = factory.MakeFileEntry(fileName);
  •             entry.DateTime = DateTime.Now;
  •             ZipStream.PutNextEntry(entry);

  •             byte[] buffer = new byte[65536];

  •             int sourceBytes;
  •             do
  •             {
  •                 sourceBytes = fileStream.Read(buffer, 0, buffer.Length);
  •                 ZipStream.Write(buffer, 0, sourceBytes);
  •             }
  •             while (sourceBytes > 0);


  •         }

  •         public void AddDirectory(string directoryName)
  •         {
  •             ZipEntry entry = factory.MakeDirectoryEntry(directoryName);
  •             ZipStream.PutNextEntry(entry);
  •         }

  •         public void Finish()
  •         {
  •             if (!ZipStream.IsFinished)
  •             {
  •                 ZipStream.Finish();
  •             }
  •         }

  •         public void Close()
  •         {
  •             Dispose(true);
  •             GC.SuppressFinalize(this);
  •         }

  •         public void Dispose()
  •         {
  •             this.Close();
  •         }

  •         protected virtual void Dispose(bool disposing)
  •         {
  •             if (!disposed)
  •             {
  •                 if (disposing)
  •                 {
  •                     if (ZipStream != null)
  •                         ZipStream.Dispose();
  •                 }
  •             }

  •             disposed = true;
  •         }
  •     }
  • }
  

  接下来,写一个SPExtensions.cs的类,用于向Microsoft.SharePoint对象添加一些扩展方法。这个类基本就是添加一些简单的方法到SPListItem类和SPList类。针对SPListItem类,我添加了一个方法用于判断是否SPListItem实例是一个文件夹,SPList类用于判断这个列表仅仅是一个文档。
  SPExtensions的代码如下:
  
SPExtensions.cs
  

  


  • using System;
  • using System.Collections.Generic;
  • using System.Linq;
  • using System.Text;
  • using System.Runtime.CompilerServices;
  • using Microsoft.SharePoint;

  • namespace DeviantPoint.DownloadZip
  • {
  •     public static class SPExtensions
  •     {
  •         public static bool IsFolder(this SPListItem item)
  •         {
  •             return (item.Folder != null);
  •         }

  •         public static bool IsDocumentLibrary(this SPList list)
  •         {
  •             return (list.BaseType == SPBaseType.DocumentLibrary);
  •         }
  •     }
  • }
  

  接下来要做的是添加一个“SharePoint映射文件夹”到项目,映射到Layouts目录(位于SharePoint根目录下)。在添加完SharePoint的“Layouts”映射文件夹后,我添加了一个SharePoint 2010 应该程序页DownloadZip.aspx到DeviantPoint.DownloadZip子文件夹,该页面负责处理来自客户端的请求并生成对应的zip文件返回到客户端。它的功能如同已知的在SharePoint 2010 Ribbon菜单中的“下载副本”的功能。来自客户端的POST请求会被发送到我的DownloadZip.aspx页面,然后这个页面把一些文档进行打包压缩到一个zip文件然后发送到客户端浏览器。这个页面需要两个参数:
  · sourceUrl –完整的文档(文件夹,包含子文件夹),请求的来源

  
· itemIDs – 列表项ID ,用分号隔开的一个SPListItem>  
该应用程序页的基本功能是根据传递过来的id检索对应的SharePoint中的文档项,使用ZipBuilder 类把检索到的文档打包成一个zip文件。如果是一个文件夹的id,则会创建文件夹(最终保存到zip文件中),并依次检索文件夹下的所有文件
  下面是DownloadZip.aspx 应用程序页的后置代码 :
  


  • using System;
  • using System.IO;
  • using System.Web;
  • using Microsoft.SharePoint;
  • using Microsoft.SharePoint.WebControls;
  • using ICSharpCode.SharpZipLib.Zip;

  • namespace DeviantPoint.DownloadZip.Layouts.DeviantPoint.DownloadZip
  • {
  •     public partial class DownloadZip : LayoutsPageBase
  •     {
  •         protected void Page_Load(object sender, EventArgs e)
  •         {
  •             string fullDocLibSourceUrl = Request.Params["sourceUrl"];
  •             if (string.IsNullOrEmpty(fullDocLibSourceUrl)) return;

  •             string docLibUrl = fullDocLibSourceUrl.Replace(SPContext.Current.Site.Url, "");

  •             SPList list = SPContext.Current.Web.GetList(docLibUrl);
  •             if (!list.IsDocumentLibrary()) return;

  •             string pItemIds = Request.Params["itemIDs"];
  •             if (string.IsNullOrEmpty(pItemIds)) return;

  •             SPDocumentLibrary library = (SPDocumentLibrary)list;

  •             string[] sItemIds = pItemIds.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
  •             int[] itemsIDs = new int[sItemIds.Length];
  •             for (int i = 0; i < sItemIds.Length; i++)
  •             {
  •                 itemsIDs = Convert.ToInt32(sItemIds);
  •             }

  •             if (itemsIDs.Length > 0)
  •             {
  •                 using (MemoryStream ms = new MemoryStream())
  •                 {
  •                     using (ZipFileBuilder builder = new ZipFileBuilder(ms))
  •                     {
  •                         foreach (int id in itemsIDs)
  •                         {
  •                             SPListItem item = library.GetItemById(id);
  •                             if (item.IsFolder())
  •                                 AddFolder(builder, item.Folder, string.Empty);
  •                             else
  •                                 AddFile(builder, item.File, string.Empty);
  •                         }

  •                         builder.Finish();
  •                         WriteStreamToResponse(ms);
  •                     }
  •                 }
  •             }

  •         }

  •         private static void AddFile(ZipFileBuilder builder, SPFile file, string folder)
  •         {
  •             using (Stream fileStream = file.OpenBinaryStream())
  •             {
  •                 builder.Add(folder + &quot;\\&quot; + file.Name, fileStream);
  •                 fileStream.Close();
  •             }
  •         }

  •         private void AddFolder(ZipFileBuilder builder, SPFolder folder, string parentFolder)
  •         {
  •             string folderPath = parentFolder == string.Empty ? folder.Name : parentFolder + &quot;\\&quot; + folder.Name;
  •             builder.AddDirectory(folderPath);

  •             foreach (SPFile file in folder.Files)
  •             {
  •                 AddFile(builder, file, folderPath);
  •             }

  •             foreach (SPFolder subFolder in folder.SubFolders)
  •             {
  •                 AddFolder(builder, subFolder, folderPath);
  •             }
  •         }

  •         private void WriteStreamToResponse(MemoryStream ms)
  •         {
  •             if (ms.Length > 0)
  •             {
  •                 string filename = DateTime.Now.ToFileTime().ToString() + &quot;.zip&quot;;
  •                 Response.Clear();
  •                 Response.ClearHeaders();
  •                 Response.ClearContent();
  •                 Response.AddHeader(&quot;Content-Length&quot;, ms.Length.ToString());
  •                 Response.AddHeader(&quot;Content-Disposition&quot;, &quot;attachment; filename=&quot; + filename);
  •                 Response.ContentType = &quot;application/octet-stream&quot;;

  •                 byte[] buffer = new byte[65536];
  •                 ms.Position = 0;
  •                 int num;
  •                 do
  •                 {
  •                     num = ms.Read(buffer, 0, buffer.Length);
  •                     Response.OutputStream.Write(buffer, 0, num);
  •                 }

  •                 while (num > 0);

  •                 Response.Flush();
  •             }
  •         }
  •     }
  • }
  

  在创建完应用程序页后,我添加一个SharePoint 2010 空白元素DownloadZip到项目中,打开Elements.xml
  代码如下
  




  •    
  •         
  •             
  •                
  •                     
  •                
  •             
  •             
  •                
  •             
  •         
  •    
  •    

  

  对此CommandUIDefinition, 我设置 Location attribute 为&quot;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 的源码:
  


  • function enable() {
  •     var items = SP.ListOperation.Selection.getSelectedItems();
  •     var itemCount = CountDictionary(items);
  •     return (itemCount > 0);

  • }

  • function downloadZip() {

  •     var context = SP.ClientContext.get_current();
  •     this.site = context.get_site();
  •     this.web = context.get_web();
  •     context.load(this.site);
  •     context.load(this.web);
  •     context.executeQueryAsync(
  •         Function.createDelegate(this, this.onQuerySucceeded),
  •         Function.createDelegate(this, this.onQueryFailed)
  •     );
  • }

  • function onQuerySucceeded() {

  •     var items = SP.ListOperation.Selection.getSelectedItems();
  •     var itemCount = CountDictionary(items);

  •     if (itemCount == 0) return;

  •     var ids = &quot;&quot;;
  •     for (var i = 0; i < itemCount; i++) {
  •         ids += items.id + &quot;;&quot;;
  •     }

  •     //send a request to the zip aspx page.
  •     var form = document.createElement(&quot;form&quot;);
  •     form.setAttribute(&quot;method&quot;, &quot;post&quot;);
  •     form.setAttribute(&quot;action&quot;, this.site.get_url() + this.web.get_serverRelativeUrl() + &quot;/_layouts/deviantpoint.downloadzip/downloadzip.aspx&quot;);

  •     var hfSourceUrl = document.createElement(&quot;input&quot;);
  •     hfSourceUrl.setAttribute(&quot;type&quot;, &quot;hidden&quot;);
  •     hfSourceUrl.setAttribute(&quot;name&quot;, &quot;sourceUrl&quot;);
  •     hfSourceUrl.setAttribute(&quot;value&quot;, location.href);
  •     form.appendChild(hfSourceUrl);

  •     var hfItemIds = document.createElement(&quot;input&quot;)
  •     hfItemIds.setAttribute(&quot;type&quot;, &quot;hidden&quot;);
  •     hfItemIds.setAttribute(&quot;name&quot;, &quot;itemIDs&quot;);
  •     hfItemIds.setAttribute(&quot;value&quot;, ids);
  •     form.appendChild(hfItemIds);

  •     document.body.appendChild(form);
  •     form.submit();
  • }

  • function onQueryFailed(sender, args) {
  •     this.statusID = SP.UI.Status.addStatus(&quot;Download as Zip:&quot;,
  •         &quot;Downloading Failed: &quot; + args.get_message() + &quot; Close.&quot;, true);
  •     SP.UI.Status.setStatusPriColor(this.statusID, &quot;red&quot;);
  • }

  • function closeStatus() {
  •     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



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-671531-1-1.html 上篇帖子: 在InfoPath中使用重复表然后按照日期过滤sharepoint列表内容 下篇帖子: 一步一步SharePoint 2007之四十八:实现Excel Service(3)——调用Excel Service
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表