Web程序导出Excel文档

版权声明:欢迎评论和转载,转载请注明来源。 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,这样似乎不能实现。

如下图所示:

Web程序导出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,非常方便。完全满足合并单元格(合并行、合并列)的需求。




上一篇:版本控制工具之SVN


下一篇:常用iOS的第三方框架