导出Excel 批量大数据异步多线程

最近接了一个新需求,主要有三个功能:

1.导出1688店铺的订单
2.导出入住微供市场店铺的商品
3.给微供市场进行下订单



其中如何调用阿里的接口进行数据获取这里就不做介绍了,但是如果有同学需要这方面的帮助可以联系我。
这里主要讲述如何导出excel。
最先开始的思路就是通过接口获取到订单信息之后通过页面Response进行输出一个Excel.
新建一个aspx页面。然后写一个方法如下:

        /// 
        /// 导出Excel
        /// 
        /// 
        /// 
        private void ExportExcel(List lst, string loginId)
        {

            string name = string.Format("{0}{1}订单报表.xls", loginId, DateTime.Now.ToString("yyMMddHHmmss"));
            HttpContext.Current.Response.Clear();
            string styleText = @" ";
            HttpContext.Current.Response.Charset = "UTF-8";
            HttpContext.Current.Response.ContentEncoding = Encoding.UTF8;//注意编码
            HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(name, Encoding.UTF8).ToString());
            HttpContext.Current.Response.ContentType = "application/ms-excel";
            var sbHtml = new StringBuilder();
            sbHtml.Append("");
            sbHtml.Append("");
            var lstTitle = new List { "订单编号", "订单状态", "买家id", "买家联系电话", "买家收货地址", "创建时间","付款时间","商品ID",
                "分类编号","商品名称", "数量", "商品单价", "付款时分摊后的每笔子订单金额", "产品金额", "折扣价",
                "产品打折单价",  "明细单价","卖家公司名称","运单号码","物流编号","物流公司","收货人姓名","收货手机","收货电话","收货省","收货市","收货区","收货地址" };
            foreach (var item in lstTitle)
            {
                sbHtml.AppendFormat("", item);
            }
            sbHtml.Append("");
            if (lst != null && lst.Count > 0)
            {
                foreach (var item in lst)
                {
                    sbHtml.Append("");
                    sbHtml.AppendFormat("", item.id);
                    sbHtml.AppendFormat("", item.statusDisPlay);
                    sbHtml.AppendFormat("", item.buyerLoginId);
                    sbHtml.AppendFormat("", string.Empty);
                    sbHtml.AppendFormat("", item.toArea);
                    sbHtml.AppendFormat("", Utility.ChangeDate(item.gmtCreate));
                    sbHtml.AppendFormat("", Utility.ChangeDate(item.gmtPayment));
                    sbHtml.AppendFormat("", item.itemId.ToString());
                    sbHtml.AppendFormat("", item.categoryId.ToString());
                    sbHtml.AppendFormat("", item.productName);
                    sbHtml.AppendFormat("", item.quantity);
                    sbHtml.AppendFormat("", item.price);
                    sbHtml.AppendFormat("", item.actualPayFee);
                    sbHtml.AppendFormat("", item.amount);
                    sbHtml.AppendFormat("", item.discount);
                    sbHtml.AppendFormat("", item.discountPrice);
                    sbHtml.AppendFormat("", item.unitPrice);
                    sbHtml.AppendFormat("", item.sellerCompanyName);
                    sbHtml.AppendFormat("", item.logisticsBillNo);
                    sbHtml.AppendFormat("", item.logisticsId);
                    sbHtml.AppendFormat("", item.logisticsCompanyName);
                    sbHtml.AppendFormat("", item.receiverName);
                    sbHtml.AppendFormat("", item.receiverMobile);
                    sbHtml.AppendFormat("", item.receiverPhone);
                    sbHtml.AppendFormat("", item.receiverProvince);
                    sbHtml.AppendFormat("", item.receiverCity);
                    sbHtml.AppendFormat("", item.receiverCounty);
                    sbHtml.AppendFormat("", item.receiverAddress);
                    sbHtml.Append("");
                }
            }
            sbHtml.Append("
{0}
{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}
"); var charset = ""; HttpContext.Current.Response.Write(charset + styleText + sbHtml.ToString()); HttpContext.Current.Response.End(); }

其中遇到了几个问题:

问题1:当列的值是一个long长整型的时候,打开excel的时候就会显示成科学计数法,如图产品编号就变成科学计数的方式显示了。
导出Excel 批量大数据异步多线程_第1张图片
问题2:结果导出Excel 真实数据才几十KB.但是Excel文件却有好几百。原因就是输除了大量的html标签。下图是一个200行数据的文件,相差已经是258kb 和41kb的区别了,当2000行的时候差距更明显。
问题3:点击了导出按钮,跳转到导出页面,执行导出相关代码流程,客户端一直等待服务器响应结束,但是因为数据太多处理时间需要几分钟甚至十几分钟,这样就会出现响应超时。




问题1解决办法:导出的额时候给td加一个样式。

string styleText = @".text{ mso-number-format:'\@'; }

问题2解决办法:使用了一个第三方操作excel的类库 NPOI ,http://npoi.codeplex.com/releases 类库地址,有源码。

        /// 
        /// 导出Excel
        /// 
        /// 
        /// 
        private void ExportExcel(List lst, string loginId)
        {
            string name = string.Format("{0}销售商品列表.xls", loginId);
            var lstTitle = new List { "产品编号", "状态", "标题", "业务类型", "SKU", "specId", "单品货号", "属性", "单价", "建议零售价", "可销售数量", "单位", "发货地址ID", "运费模板ID", "体积", "产品链接" };

            NPOI.HSSF.UserModel.HSSFWorkbook book = new NPOI.HSSF.UserModel.HSSFWorkbook();//创建工作簿
            NPOI.SS.UserModel.ISheet sheet = book.CreateSheet("销售商品列表");//创建sheet
            NPOI.SS.UserModel.IRow row = sheet.CreateRow(0);//创建表头第一行
            for (int i = 0; i < lstTitle.Count; i++)
            {
                row.CreateCell(i).SetCellValue(lstTitle[i]);//循环创建单元格并且赋值
            }
            for (int j = 0; j < lst.Count; j++)
            {
                NPOI.SS.UserModel.IRow rowt = sheet.CreateRow(j + 1);
                var rcol = rowt.CreateCell(0);
                rcol.SetCellType(NPOI.SS.UserModel.CellType.String);
                rcol.SetCellValue(lst[j].productID.ToString());              
                var rco15 = rowt.CreateCell(15);
                HSSFHyperlink link = new HSSFHyperlink(HyperlinkType.Url);//建一个HSSFHyperlink实体,指明链接类型为URL(这里是枚举,可以根据需求自行更改)  
                link.Address = string.Format(@"https://detail.1688.com/offer/{0}.html", lst[j].productID);//给HSSFHyperlink的地址赋值  
                rco15.Hyperlink = link;//将链接方式赋值给单元格的Hyperlink即可将链接附加到单元格上                   
                rco15.SetCellValue("链接");
            }
            using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
            {
                book.Write(ms);
                Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}.xls", name));
                Response.BinaryWrite(ms.ToArray());
                book = null;
                ms.Close();
                ms.Dispose();
                Response.End();
            }
        }

使用NPOI 进行导出Excel 同时也解决了第一个问题。
问题3解决办法:只能通过异步的方式去做了。


大致思路就是通过接口查询出订单然后生成一个excel文件在本地然后提供下载链接。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

namespace Ali1688.Web
{
    /// 
    /// 生成Excel类
    /// 
    public static class ExportExcelManager
    {
        //全局静态变量用来保存当前执行的logs
        public static List ExportLogs = new List();

        /// 
        /// 导出单个店铺的订单
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static void Report(DateTime dts, DateTime dte, string memberId, string refreshToken, string accessToken, string loginId)
        {
            ExportLogs.Clear();
            ExportLogs.Add("开始导出" + loginId + dts.ToString("yyyy-MM-dd") + "到" + dte.ToString("yyyy-MM-dd") + "的订单");
            List lst = new List();
            lst = GetOrdersItem(memberId, accessToken, dts, dte);
            ExportLogs.Add("订单获取完成开始生成Excel...");
            string name = loginId + dts.ToString("yyyy-MM-dd") + "到" + dte.ToString("yyyy-MM-dd");
            ExportExcel(lst, name, false);
        }

        /// 
        /// 导出Excel
        /// 
        /// 
        /// 
        private static void ExportExcel(List lst, string loginId, bool isBatch = true)
        {

            string name = string.Format("{0}订单报表{1}.xls", loginId, DateTime.Now.ToString("yyyyMMddHHmmss"));
            var lstTitle = new List { "订单编号", "订单状态", "买家id", "买家联系电话", "买家收货地址", "创建时间","付款时间","商品ID",
                 "分类编号","商品名称", "数量", "商品单价", "付款时分摊后的每笔子订单金额", "产品金额", "折扣价",
                 "产品打折单价",  "明细单价","卖家公司名称","运单号码","物流编号","物流公司","收货人姓名","收货手机","收货电话","收货省","收货市","收货区","收货地址" };
            NPOI.HSSF.UserModel.HSSFWorkbook book = new NPOI.HSSF.UserModel.HSSFWorkbook();
            NPOI.SS.UserModel.ISheet sheet = book.CreateSheet("订单列表");
            NPOI.SS.UserModel.IRow row = sheet.CreateRow(0);
            for (int i = 0; i < lstTitle.Count; i++)
            {
                row.CreateCell(i).SetCellValue(lstTitle[i]);
            }
            ExportLogs.Add("共需要生成" + lst.Count + "条明细!");
            for (int j = 0; j < lst.Count; j++)
            {
                NPOI.SS.UserModel.IRow rowt = sheet.CreateRow(j + 1);
                //创建单元格
                ExportLogs.Add("生成完成" + (j + 1) + " 条明细!");
            }
            ExportLogs.Add("所有明细生成完成,生成文件中。。。");
            // 写入到客户端  
            using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
            {
                book.Write(ms);
                string path = System.AppDomain.CurrentDomain.BaseDirectory + (isBatch ? "/BatchReport/" : "/Report/") + name;
                var dir = System.AppDomain.CurrentDomain.BaseDirectory + (isBatch ? "/BatchReport" : "/Report");
                if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
                using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write))
                {
                    byte[] data = ms.ToArray();
                    fs.Write(data, 0, data.Length);
                    fs.Flush();
                }
                book = null;
            }
            ExportLogs.Add("生成Excel文件完成!请点击下载");
        }

        /// 
        /// 获取这个商铺的销售订单
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        private static List GetOrdersItem(string memberId, string accessToken, DateTime dts, DateTime dte)
        {
            //获取订单具体方法
            throw new NotImplementedException();
        }
    }
}

调用代码:

   Thread thread = new Thread(() => ExportExcelManager.Report(dts, dte, memberId, refreshToken, accessToken, loginId));
               thread.Start();

最后来几张图片吧

1.主页面:

导出Excel 批量大数据异步多线程_第2张图片


2.导出页面
导出Excel 批量大数据异步多线程_第3张图片
3.导出成功
导出Excel 批量大数据异步多线程_第4张图片

最后其实还有一个问题我没有解决掉,就是这个提示,其实是一个全局的静态变量。所以多个用户同时操作的时候会出现提示不准确。但是这个需求是我们内部的人员使用而且只是提示上面的不准确。
如果谁有好的提议可提出来我修改。

你可能感兴趣的:(导出Excel 批量大数据异步多线程)