版權聲明:歡迎評論和轉載,轉載請注明來源。 https://blog.csdn.net/zy332719794/article/details/8938475
今天接到一個任務,把資料庫裡面的資料導出到Excel文檔。系統是Web程式的,使用的是MVC架構。第一個想法是很簡單,儲存.csv檔案。做法是首先把資料讀到一個DataTable裡面,然後将資料分隔寫入檔案就OK了,最後在相應請求下載下傳檔案。
代碼如下:
/// <summary>
/// 導出資料
/// </summary>
public ActionResult ExportData(int processId)
{
var myProcessId = processId;
var items = db.NecessaryMaterialsDbSet.Include(p => p.ProcessItem)
.OrderBy(p => p.Category)
.ToList()
.Where(p => p.ProcessItem.Id == processId);
if (!items.Any())
{
return RedirectToAction("Index", new { processId = myProcessId });
}
var dt = new DataTable();
dt.Columns.Add("類别");
dt.Columns.Add("材料名稱");
dt.Columns.Add("材料來源");
dt.Columns.Add("來源類型");
dt.Columns.Add("原件、影印件");
dt.Columns.Add("備注");
foreach (var materialse in items)
{
dt.Rows.Add(materialse.Category,
materialse.Name,
materialse.Source,
materialse.SourceType,
materialse.OriginalOrCopy,
materialse.Note);
}
//生成檔案
string fileName = items.First().ProcessItem.ProcessName + "-必備材料.csv";
var sw = new StringWriter();
var title = new StringBuilder();
title.Append(dt.Columns[0].ColumnName);
for (int i = 1; i < dt.Columns.Count; i++)
{
title.AppendFormat(",{0}", dt.Columns[i].ColumnName);
}
sw.WriteLine(title);
var content = new StringBuilder();
foreach (DataRow row in dt.Rows)
{
content.Append(row[0]);
for (int i = 1; i < dt.Columns.Count; i++)
{
content.AppendFormat(",{0}", row[i]);
}
sw.WriteLine(content);
content.Clear();
}
sw.Close();
Response.AddHeader("Content-Disposition", "attachment; filename=" + Server.UrlEncode(fileName));
Response.ContentType = "vnd.ms-excel.numberformat:yyyy-MM-dd ";
Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");
Response.Write(sw);
Response.End();
return RedirectToAction("Index", new { processId = myProcessId });
}
但是有個問題,我需要導出有合并單元格的樣式的Excel,這樣似乎不能實作。
如下圖所示:
第一個想法是使用Office的Excel的API,有個同僚建議使用Table來構造。結果試了下,果然不錯。
構造方法如在html裡面構造一樣。使用<table><tr><tb>标簽來控制行和列以及内容。
同時還可以在table裡面設定屬性,如<table border='1'>、<td width='100'><br>等等。
其中跨行就用rowspan屬性來設定,如:"<td rowspan=5>表示跨5行(合并單元格)。
原來還有這樣好的方法,于是按照這種方式寫了代碼,調試生成,效果非常好,上面的圖就是用table的方法生成的。
下面我貼上一些執行個體代碼:
ExpMaterialsToExcelModel.cs(這個是用來存将導出的資料類結構)
public class ExpMaterialsToExcelModel
{
/// <summary>
/// 流程名稱
/// </summary>
public string Name { get; set; }
/// <summary>
/// 審批事項
/// </summary>
public List<Category> Categorys { get; set; }
public ExpMaterialsToExcelModel()
{
Categorys = new List<Category>();
}
}
public class Category
{
/// <summary>
/// 審批事項名稱
/// </summary>
public string Name { get; set; }
/// <summary>
/// 承辦科室
/// </summary>
public string Department { get; set; }
/// <summary>
/// 聯系人及電話
/// </summary>
public string PersonAndPhone { get; set; }
/// <summary>
/// 材料
/// </summary>
public List<MaterialsInfo> MaterialsList { get; set; }
public Category()
{
MaterialsList = new List<MaterialsInfo>();
}
}
public class MaterialsInfo
{
/// <summary>
/// 排号順序
/// </summary>
public int SortNumb { get; set; }
/// <summary>
/// 材料名稱
/// </summary>
public string Name { get; set; }
/// <summary>
/// 來源類型
/// </summary>
public string SourceType { get; set; }
/// <summary>
/// 來源
/// </summary>
public string Source { get; set; }
/// <summary>
/// 備注
/// </summary>
public string Note { get; set; }
}
ExpMaterialsToExcelModel.cs(從資料庫讀取資料)
private ExpMaterialsToExcelModel GetExpData(int processId)
{
代碼略。。。
}
GetExpString(生成導出的table文本)重點
private StringBuilder GetExpString(ExpMaterialsToExcelModel tableData)
{
int rowCount = tableData.Categorys.Sum(category => category.MaterialsList.Count);
var str = new StringBuilder();
str.Append("<meta http-equiv=\"content-type\" content=\"application/excel;charset=utf-8\" />");
str.Append("<table border='1'>");
str.Append("<tr>");
str.AppendFormat("<td width='100' rowspan='{0}'>{1}</td>", rowCount, tableData.Name);
for (int i = 0; i < tableData.Categorys.Count; i++)
{
if (i > 0)
{
str.Append("<tr>");
}
var category = tableData.Categorys[i];
rowCount = category.MaterialsList.Count;
str.AppendFormat("<td width='100' rowspan='{0}'>{1}</td>", rowCount, category.Name);
str.AppendFormat("<td width='100'>{0}</td>", category.MaterialsList[0].SourceType);
str.AppendFormat("<td width='200'>{0}.{1}</td>", category.MaterialsList[0].SortNumb,
category.MaterialsList[0].Name);
str.AppendFormat("<td width='100'>{0}</td>", category.MaterialsList[0].Note);
str.AppendFormat("<td width='100' rowspan='{0}'>{1}</td>", rowCount, category.Department);
str.AppendFormat("<td width='100' rowspan='{0}'>{1}</td>", rowCount, category.PersonAndPhone);
str.Append("</tr>");
for (int j = 1; j < category.MaterialsList.Count; j++)
{
str.Append("<tr>");
str.AppendFormat("<td width='100'>{0}</td>", category.MaterialsList[j].SourceType);
str.AppendFormat("<td width='200'>{0}.{1}</td>", category.MaterialsList[j].SortNumb,
category.MaterialsList[j].Name);
str.AppendFormat("<td width='100'>{0}</td>", category.MaterialsList[j].Note);
str.Append("</tr>");
}
}
str.Append("</table>");
return str;
}
ExportData方法(頁面請求,傳回和下載下傳檔案)
/// <summary>
/// 導出資料
/// </summary>
public ActionResult ExportData(int processId)
{
var tableData = GetExpData(processId);
var tableString = GetExpString(tableData);
// 輸出Excel
string fileName = tableData.Name + "材料清單";
Response.ClearContent();
Response.AddHeader("content-disposition",
string.Format("attachment; filename={0}.xls",
HttpUtility.UrlEncode(fileName, Encoding.UTF8)));
Response.ContentType = "application/excel";
Response.Charset = "utf-8";
Response.Write(tableString);
Response.End();
var myProcessId = processId;
return RedirectToAction("Index", new { processId = myProcessId });
}
這種方法省去了去調用繁瑣的Excel API,非常友善。完全滿足合并單元格(合并行、合并列)的需求。