我做的功能

        这些天我做了一个下载Excel,上传Excel的功能,代码是抄的,控件是现成的,我就是把他们放一块了.先说下载Excel,就是从数据库中读出一些数据,然后将这些数据放到Excel,最后就可以下载到本地了.

         前台代码就是一个链接,然后这个链接的JS方法就是调用一个一般处理程序,在一般处理程序中写我那段拼凑Excel的代码.

         首先将需要导出的数据拿出来,也就是Excel中的那几个字段,就比如我的需要员工编号,姓名,身份证号,组织和奖金金额.前面四项需要我从数据库中读出,而奖金金额则是应该下载完Excel后手动填写的.如果没有任何一张实体是和这个对应的,你可以选择自己建一个实体,并建一个该实体的集合类.集合类里可以不写任何方法

[Serializable]
    public classEmployeeDividedBonusImportTrans
    {
 
        /// <summary>
        /// 员工Code
        /// </summary>
        public string EmployeeCode { get; set;}
 
        /// <summary>
        /// 员工编号
        /// </summary>
        [Description("员工编号")]
        public string EmployeeIDNumber { get;set; }
 
        /// <summary>
        /// 身份证号
        /// </summary>
       [Description("证件号")]
        public string IdentityCardCode { get;set; }
 
        /// <summary>
        /// 员工姓名
        /// </summary>
        [Description("员工姓名")]
        public string EmployeeName { get; set;}
 
        /// <summary>
        /// 业务组织
        /// </summary>
        [Description("业务组织")]
        public string OrgName { get; set; }
 
        /// <summary>
        /// 年终奖金额
        /// </summary>
        [Description("年终奖金")]
        public decimal Amount { get; set; }
    }</span>

         而集合类就是这样

   [Serializable]
    public classEmployeeDividedBonusImportTransCollection :
   EditableDataObjectCollectionBase<EmployeeDividedBonusImportTrans>
    {
    } 

        这样就能体现EmployeeDividedBonusImportTransEmployeeDividedBonusImportTransCollection是有一对多关系的.

         实体类和集合类都准备好了之后,就该考虑一般处理程序的功能了,他的主要功能1,生成导出信息;2.将生成的导出信息生成到excel;3.下载excel.

importCol =importCol.GenerateImportDetail(form.UnitCode);
 
            if (importCol != null)
            {
                byte[] excel =importCol.ToExcel();
               PageExtension.DownloadBytes(excel,string.Format("[{0}]的年终奖金额导出.xlsx", form.UnitName));
            }

        代码掐头去尾,根据命名大概能知道importCol就是集合类,然后在集合类中有GenerateImportDetail(),生成导出信息;ToExcel(),生成Excel和在PageExtension中有DownloadBytes下载Excel 3个方法.

         对于GenerateImportDetail(),所做的功能就是,将实体类的字段值填满(除奖金金额),然后实体类变成集合.返回集合就可以了.

         ToExcel就是

     /// <summary>
        /// 生成Excel
        /// </summary>
        /// <returns></returns>
        public byte[] ToExcel()
        {
            string[] dataName = {"EmployeeIDNumber", "OrgName","IdentityCardCode", "EmployeeName", "Amount" };
            //集合转换为datatable
            DataTable data =DataTableExtension.ToDataTable(this, dataName);
            byte[] template =DocumentHelper.CreateDocumentAndTable("Sheet1", "A1","EmployeeDividedBonusImport", data.AsDataView(),ExcelTableStyles.Custom);
            return template;
        }

             显示将5个列变为Datatable,然后将那个datatable变为填充好数据变成数组返回.

///<summary>
        /// 转换为DataView 列名使用属性名,列Caption使用DescriptionAttribute
        /// </summary>
        /// <typeparamname="T">元素类型</typeparam>
        /// <paramname="items">集合</param>
        /// <paramname="propertyTypeNames"> </param>
        /// <returns></returns>
        public static DataTableToDataTable<T>(IEnumerable<T> items, params string[]propertyTypeNames)
        {
            //首先验证不能为空
            items.NullCheck("items");
            //然后将传入的数据的类型取出,因为this是集合类型,而集合类型继承的EditableDataObjectCollectionBase继承了IEnumerable<T>. T是实体类型
            Type type = typeof(T);
                          
            //取得表结构
            DataTable table =GetTableStruct(type, propertyTypeNames);
                         
            //然后将items也就是集合中的数据一条一条写到datatable中
            //使用lamda表达式,obj就是集合中的实体类,一条一条遍历集合中的数据.
            items.ForEach(obj =>
            {
                //先创建一行,然后给这一行赋值,最后一行一行都填充好了就变成table了
                DataRow row = table.NewRow();
                //获取到实体类型的属性,遍历属性信息
                foreach (PropertyInfo prop intype.GetProperties())
                {
                    //如果实体类的属性名和表的列名是一样的,就把该属性上的值,给拿出来赋给该列
                    if(table.Columns.Contains(prop.Name))
                    {
                        //将属性上的值拿出
                        object columnValue =prop.GetValue(obj, null);
                        //如果列是时间,并且是最小的时间,那么就让他为null
                        if (columnValue isDateTime && ((DateTime)columnValue) == DateTime.MinValue)
                        {
                            columnValue =DBNull.Value;
                        }
                         //最后给对应的列赋值
                        row[prop.Name] =columnValue;
                    }
                }
                //最后行组合成表
                table.Rows.Add(row);
            });
            //提交datatable的更改
            table.AcceptChanges();
            //最后返回填充好了数据的datable
            return table;
        }

           生成了table之后,还要将table中的数据填充到exceltable

/// <summary>
///创建文档,并将数填充到ExcelTable中
///</summary>
///<param name="worksheetName">工作表名称</param>
///<param name="beginAddress">开始单元格</param>
///<param name="tableName">ExcelTable名称</param>
///<param name="dvData">数据源</param>
///<param name="tableStyle">ExcelTable 样式</param>
///<param name="isPrintHeaders"></param>
///<returns></returns>
publicstatic byte[] CreateDocumentAndTable(string worksheetName, string beginAddress,string tableName, System.Data.DataView dvData, ExcelTableStyles tableStyle)
{
//创建一个工作簿
WorkBookworkbook = WorkBook.CreateNew();
 //创建工作单
WorkSheetworksheet = workbook.Sheets["sheet1"];
 //给工作单命名
if(worksheetName.IsNotEmpty())
worksheet.Name= worksheetName;
//给databview的table命名
dvData.Table.TableName= tableName;
//将dvData中的数据填充到工作单中,往里看了下,没完没了了.
worksheet.LoadFromDataView(CellAddress.Parse(beginAddress),tableStyle, dvData, null);
 
//最后将工作簿转为二进制输出
returnworkbook.SaveAsBytes();
}

而将转为二进制输出是这样做的,

///<summary>
///将文件转换成二进制输出
///</summary>
///<returns></returns>
publicbyte[] SaveAsBytes()
{
//首先得有二进制的对象
Byte[]byRet = null;
using(MemoryStream excelStream = new MemoryStream())
{
Save(excelStream);
 
byRet= new byte[excelStream.Length];
longpos = excelStream.Position;
excelStream.Read(byRet,0, (int)excelStream.Length);
excelStream.Seek(pos,SeekOrigin.Begin);
 
returnbyRet;
}
}

核心是这一句,excelStream.Read(byRet,0, (int)excelStream.Length);0开始,将文件整个读到byRet,最后返回.


            差不多从ToExcel中出来了,数据都填充好了,那么现在就是下载excel.

PageExtension.DownloadBytes(excel,string.Format("[{0}]的年终奖金额导出.xlsx", form.UnitName));

        /// <summary>
        /// 下载二进制文件, 不分段下载, 适合小文件
        /// </summary>
        /// <paramname="bytes"></param>
        /// <paramname="fileName"></param>
        public static void DownloadBytes(byte[]bytes, string fileName)
        {
            //将文件名转为unicode编码的文件名
            string encodedfileName =HttpUtility.UrlEncode(fileName, Encoding.UTF8);
            //为当前的http请求设置http上下文对象
            HttpContext context =HttpContext.Current;
            //清空http上下文的response
            context.Response.Clear();
            //设置输出流的http MIME类型
            context.Response.ContentType =MediaTypeNames.Text.Xml;
            //将http头添加到输出流
           context.Response.AppendHeader("content-disposition","attachment;fileName=" + encodedfileName);
           //将二进制写入http输出流
           context.Response.BinaryWrite(bytes);
           //context.Response.End();
           //结束
           context.ApplicationInstance.CompleteRequest();
 
        }

           核心就是

context.Response.AppendHeader("content-disposition","attachment;fileName=" + encodedfileName);
context.Response.BinaryWrite(bytes);

         将文件名设置好,然后将二进制的bytes写入http输出流.

         然后文件就可以下载了.总结一小下,不深入不知道,一深入吓一跳.每段代码看起来都不多哦,看起来很简单哦,但是每个方法调了另一个方法,另一个方法调了另一个方法,然后就这样没玩没了了.封装的真是吓人,也确实是相当方便,我本身只用写一点代码,就能完成下载excel的功能.但是我所用的那一点代码,背后却是封装了无数的方法.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值