目 錄:基于NPOI的報表引擎——ExcelReport
上一篇:使用ExcelReport導出Excel
下一篇:擴展元素格式化器
針對上一篇隨筆收到的反饋,在展開對ExcelReport源碼解析之前,我認為把編寫該組件時的想法分享給大家是有必要的。
編寫該組件時,思考如下:
為什么要將樣式、格式與數據分離呢?恩,你不妨想一想在生成報表時,那些是變的而那些又是不變的。我的結論是:變的是數據。
有了這個想法,很自然的想到用模板去承載不變的部分(常量內容的樣式、格式、數據及變量內容的樣式、格式),在程序中控制變的部分(變量內容的數據)。
這里以上一篇中的例子標識:

變量內容已使用粉紅色邊框標出,其余為常量內容。好了,相信“內容的數據”大家都知道那個是那個的。下面截圖,內容的樣式和格式。


現在我們回到上篇中使用的模板,相信你應該知道它承載那些東西了。

啰嗦了這么多,總結一下樣式、格式與數據分離的好處:它讓我們編寫程序時關注更少(只需關心“變量內容的數據”)。
為什么要抽象一個“元素格式化器”的概念呢?我們看數據源,我們有可能要將某個類型的數據填充到某個單元格、也可能將一個集合填充到多行、有可能將一張圖片填充到某個位置、也有可能就將某個字符串合并到某個單元格的內容中......如此種種。那么它們有什么共同點呢?它們都是填充“變量內容的數據”到模板的。
有了上面的背景,這張UML想必不難理解了。

當然,如果你還是覺得復雜, 沒關系。我會先介紹一下這里面幾個重點關系。
這是一個靜態類,非常簡單。只有兩個靜態方法:ExportToLocal()、ExportToWeb()分別將生成的文件導出到本地和Web。這多半是廢話了,下面是重點:

這便引出了SheetFormatterContainer類,SheetFormatterContainer類是何許也?
說到這,順便說下:ElementFormatter類和SheetFormatterContext類。
回到Export:
public static byte[] ExportToBuffer(string templateFile, params SheetFormatterContainer[] containers)
{var workbook = LoadTemplateWorkbook(templateFile);
foreach (var container in containers)
{var sheet = workbook.GetSheet(container.SheetName);
var context = new SheetFormatterContext(sheet, container.Formatters);
context.Format();
}
return workbook.SaveToBuffer();
}
如上代碼,在執行導出的過程中,將每一個SheetFormatterContainer對象轉換成了SheetFormatterContext對象。然后SheetFormatterContext對象調用自身的Format()方法格式化Sheet。
public void Format()
{if (null == Sheet || null == Formatters)
{return;
}
foreach (var formatter in Formatters)
{formatter.Format(this);
}
}
Formatters就是從SheetFormatterContainer傳過來的“元素格式化器”集合。

抽象的“元素格式化器”:

至此,ExcelReport組件的核心部分已經介紹完成了,下面附上代碼(如下代碼僅供參考,了解ExcelReport組件最新動態,請到GitHub下載最新源碼)。

SheetFormatterContainer.cs
/*
類:SheetFormatterContainer
描述:Sheet中元素的格式化器集合
編 碼 人:韓兆新 日期:2015年01月17日
修改記錄:
*/
using System.Collections.Generic;
namespace ExcelReport
{public class SheetFormatterContainer
{#region 成員字段及屬性
PRivate string sheetName;
public string SheetName
{ get { return sheetName; }}
private IEnumerable<ElementFormatter> formatters;
public IEnumerable<ElementFormatter> Formatters
{ get { return formatters; }}
#endregion 成員字段及屬性
#region 構造函數
public SheetFormatterContainer(string sheetName, IEnumerable<ElementFormatter> formatters)
{this.sheetName = sheetName;
this.formatters = formatters;
}
#endregion 構造函數
}
}
SheetFormatterContext.cs
/*
類:SheetFormatterContext
描述:Sheet格式化的上下文
編 碼 人:韓兆新 日期:2015年01月17日
修改記錄:
*/
using System.Collections.Generic;
using NPOI.SS.UserModel;
namespace ExcelReport
{public class SheetFormatterContext
{#region 成員字段及屬性
private int _increaseRowsCount = 0;
public ISheet Sheet { get; set; } public IEnumerable<ElementFormatter> Formatters { get; set; }#endregion 成員字段及屬性
#region 構造函數
public SheetFormatterContext()
{}
public SheetFormatterContext(ISheet sheet, IEnumerable<ElementFormatter> formatters)
{<新聞熱點
疑難解答