同事剛加入急急如律令的專案幫忙開發報表,使用者有一項需求是列印報表時,表頭要出現頁數、標題、欄位名稱等,專案中使用的是NPOI,之前自己參加專案時都是同事寫好了元件,對NPOI操作不太熟悉,這次捲起袖子來試試。
同事的任務會讀取報表範本,然後把Row Data塞到Excel上(xlsx)。待會我們依序安裝NPOI、撰寫測試程式、製作報表範本,最後依序執行對照組及實驗組的測試。
What's NPOI
NPOI是Java POI的.NET版本,作者是對岸上海的Tony,使用的版權是Apache License 2.0 (Apache),可以商業使用。
This project is the .NET version of POI Java project at http://poi.apache.org/. POI is an open source project which can help you read/write xls, doc, ppt files. It has a wide application.
NPOI安裝
先新增一個測試專案,接著到Nuget套件管理員安裝NPOI。
配合專案,我們選2.1.3.1版本
撰寫測試程式
新增Poker.cs類別,待會測試丟這個Entity產表。
public class Poker
{
public int Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string Color { get; set; }
public Decimal Balance { get; set; }
}
打開UnitTest1.cs程式
簡單寫一段使用NPOI產生報表的方法,因為要接不同的Entity,用一點反射來處理。另外因為報表中數值,方法只先處理金額和字串。
public void Generate<T>(string TemplatePath, string ReportPath, List<T> entities, int Offset, int PageSize)
{
using (FileStream fileStream = new FileStream(TemplatePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
IWorkbook workbook = WorkbookFactory.Create(fileStream);
ISheet sheet = workbook.GetSheetAt(0);
List<ICell> TemplateCells = new List<ICell>();
for (int i = 0; i < sheet.GetRow(Offset).Cells.Count; i++)
{
TemplateCells.Add(sheet.GetRow(Offset).GetCell(i));
}
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (var entity in entities)
{
sheet.CreateRow(Offset);
int CellInRow = 0;
foreach (var property in properties)
{
ICell cell = sheet.GetRow(Offset).CreateCell(CellInRow);
cell.CellStyle = TemplateCells[CellInRow].CellStyle;
cell.SetCellType(TemplateCells[CellInRow].CellType);
if (TemplateCells[CellInRow].CellType.Equals(CellType.Numeric))
{
cell.SetCellValue(Convert.ToDouble(property.GetValue(entity, null)));
}
else
{
cell.SetCellValue(Convert.ToString(property.GetValue(entity, null)));
}
CellInRow++;
}
Offset++;
}
using (FileStream fileOut = new FileStream(ReportPath, FileMode.Create))
{
workbook.Write(fileOut);
}
}
}
繼續在測試類別UnitTest1.cs加入以下測試程式碼
[TestMethod]
public void TestGererate()
{
//(1)製造測試資料
List<Poker> Pokers = new List<Poker>();
for (int i = 0; i < 10; i++)
{
Pokers.Add(new Poker { Id = 1, Name = "David", Title = "King", Color = "Spades", Balance = 1000 });
Pokers.Add(new Poker { Id = 2, Name = "Charlemagne", Title = "King", Color = "Hearts", Balance = 2000 });
Pokers.Add(new Poker { Id = 3, Name = "Caesar", Title = "King", Color = "Diamonds", Balance = 3000 });
Pokers.Add(new Poker { Id = 4, Name = "Alexander", Title = "King", Color = "Clubs", Balance = 4000 });
Pokers.Add(new Poker { Id = 5, Name = "Athena", Title = "Queen", Color = "Spades", Balance = 5000 });
Pokers.Add(new Poker { Id = 6, Name = "Judith", Title = "Queen", Color = "Hearts", Balance = 6000 });
Pokers.Add(new Poker { Id = 7, Name = "Rachel", Title = "Queen", Color = "Diamonds", Balance = 7000 });
Pokers.Add(new Poker { Id = 8, Name = "Argine", Title = "Queen", Color = "Clubs", Balance = 8000 });
}
//(2)產生報表
string TemplatePath = @"D:\AP\Report\template\pokers.xlsx";
string ReportPath = @"D:\AP\Report\pokers.xlsx";
Generate(TemplatePath, ReportPath, Pokers, 1, 25);
Assert.AreEqual(true, File.Exists(ReportPath));
}
建立Excel範本
打開Excel,新增5個欄位,然後第二行放明細資料,最後儲存成Pokers.xlsx作為報表範本。
對照組測試
在測試總管執行選取的測試,或直接在測試方法TestGenerate按CTRL + R + T
測試成功!
報表檔案產生!
Excel預覽列印(CTRL + P)
出現幾個呈現面的問題: 表頭沒有頁數、沒有報表名稱、產表時間,第二頁缺欄位名稱等。
實驗組
簡單用Excel的版面配置設定來解題。
打開剛剛製作好的Excel範本檔案,版面配置 > 列印標題 > 頁尾頁首 > 自訂頁首
利用左中右上方的小icon插入日期、時間、頁碼及總頁數,並在畫面中央有自信的輸入
IT’S NOT A BUG,IT’S A FEATURE
版面設定的工作表處,設定標題列為第一行
Excel預覽列印(CTRL + P),重新產表後,該有的表頭、頁數、總頁數及重複的欄位名稱都給他補上了。
同事後來增加了固定每頁列印筆數、分組小計及總計的需求,今晚先掛帳,有空繼續筆記。
今天的口號是 IT'S NOT A BUG,IT'S A FEATURE!
2011.9 義大利羅馬 圓形競技場,建於公元72年至82 年
參考