• 运用Aspose.Cells组件将数据导至Execl


      工作了几年,却一直没有做过将数据导出至Execl,想想也很奇葩。

      最近我们在做一个供应链系统,这类系统,里面自然会涉及到操作Execl的功能,正好我所负责的功能里面有这个。

      导出Execl的需求大概是这样的,一个主表,一个从表,关系是一对多,主从表关联,导出的数据是主表有多少条数据,那么Execl里面就有多少行数据,这里自然会涉及到合并单元格的动作,并且数据里面还有图片列,但看这需求总结出两点:1) 合并单元格,2) 显示图片。

      最后导出的效果图截取部分:

      

      部门里面的架构组提供的导出Execl组建不支持对指定列合并单元格功能,依赖于NOPI,所以后来选择了Aspose.Cells这玩意,听说网上代码一大堆,就找了找,不过么有找到合适的,之后就去官网下了示例代码看了一些,有些代码片段还是有参考价值的。

      下面就说自己的思路了。

      1.原始数据准备

        因为主从关系,且导出行数以主表数据行数决定,所以这里用到了oracle里面的行列转换函数wm_concat,其要点是:

    select id, wm_concat(to_char(colorname)) from tb group by id
    

        因为colorname是中文,如果不加to_char函数的话,查询出来的数据会是乱码。

      2. 图片显示与合并单元格

        因为这里的图片都存在图片服务器上面,这个组件不支持网络图片,需要先将图片转换成MemoryStream,我觉得吧,这个很鸡肋。

    方法是sheet.Pictures.Add,前两个参数是起始行列,行列索引默认是从1开始的,这个需要注意下。合并单元格的方法就是sheet.Cells.Merge,前两个参数是起始行列,索引是从0开始,不知为什么要这样设计?

        还有一个我觉得很不友好的是,给单元格加边框的时候竟然分上下左右4个部分加边线,很是奇怪,下面有代码。

      3. 代码设计

        这里设计了一个接口IExeclDataExporter,里面只有一个方法void DataExport(ExporterParams exporterParams); 代码如下:

      /// <summary>
        /// Execl数据导出服务(依赖于Aspose.Cells组件)
        /// </summary>
        internal interface IExeclDataExporter
        {
            void DataExport(ExporterParams exporterParams);
        }
    
        /// <summary>
        /// 参数
        /// </summary>
        internal sealed class ExporterParams
        {
            /// <summary>
            /// Execl列头
            /// </summary>
            public IList<DataHeader> ExeclDataHeader { get; set; }
    
            /// <summary>
            /// Execl数据体
            /// </summary>
            public DataTable ExeclDataBody { get; set; }
    
            public string ExeclTitle { get; set; }
    
            /// <summary>
            /// 不需要合并列
            /// </summary>
            public string NonMergeColumnCode { get; set; }
    
            /// <summary>
            /// 图片列
            /// </summary>
            public string ImageColumnCode { get; set; }
    
            /// <summary>
            /// 导出(绝对路径)
            /// </summary>
            public string DocumentFileName { get; set; }
        }
    
        /// <summary>
        /// 列头
        /// </summary>
        internal sealed class DataHeader
        {
            /// <summary>
            /// 列显示名称
            /// </summary>
            public string DisplayName { get; set; }
    
            /// <summary>
            /// 列编码
            /// </summary>
            public string ColumnCode { get; set; }
    
            /// <summary>
            /// 列宽度
            /// </summary>
            public int ColumnWidth { get; set; }
        }
    

        实现该接口的类是ExeclDataExporter,代码是:

    internal class ExeclDataExporter:IExeclDataExporter
        {
            public void DataExport(ExporterParams eParams)
            {
                Guard.AgainstNull(eParams.ExeclDataHeader, "ExeclDataHeader");
    
                //1. 变量定义,样式
                Workbook workbook = new Workbook(); 
                DefineStyle(workbook);
    
                //2. 设置表头数据
                SetExeclHeadData(workbook, eParams.ExeclTitle, eParams.ExeclDataHeader);
    
                //3. 设置表体数据
                SetExeclBodyData(workbook, eParams);
    
                //4. 保存
                workbook.Save(eParams.DocumentFileName);
    
            }
    
            private void SetExeclHeadData(Workbook workbook, string title, IList<DataHeader> ExeclDataHeader)
            {
                Worksheet sheet = workbook.Worksheets[0];
    
                sheet.Cells.Merge(0, 0, 1, ExeclDataHeader.Count);
                sheet.Cells[0, 0].PutValue(title);
    
                Style style1 = workbook.Styles["Font25Center"];
                sheet.Cells[0, 0].SetStyle(style1);
    
                Style style2 = workbook.Styles["FontTitleCenter"];
                for (var i = 0; i < ExeclDataHeader.Count; i++)
                {
                    var head = ExeclDataHeader[i];
    
                    sheet.Cells.SetColumnWidth(i, head.ColumnWidth);
    
                    sheet.Cells[1, i].PutValue(head.DisplayName);
                    sheet.Cells[1, i].SetStyle(style2);
                }
    
                //设置当前数据行索引
                CurrentRowIndex = 2;
            }
    
            private void SetExeclBodyData(Workbook workbook, ExporterParams eParams)
            {
                var dtBody = eParams.ExeclDataBody;
    
                Style style = workbook.Styles["FontCenter"];
    
                for (var i = 0; i < dtBody.Rows.Count; i++)
                {
                    var row = dtBody.Rows[i];
    
                    //填充行数据
                    FillRowData(workbook.Worksheets[0], style, dtBody.Rows[i], eParams);
                }
            }
    
            private void FillRowData(Worksheet sheet, Style style, DataRow row, ExporterParams eParams)
            {
                //上一次当前行索引
                var oldCurrentRowIndex = CurrentRowIndex;
    
                //不合并列索引
                var nonMergeColumnIndex = GetColumnIndex(eParams.NonMergeColumnCode, eParams.ExeclDataHeader);
    
                //图片列索引
                var imageColumnIndex = GetColumnIndex(eParams.ImageColumnCode, eParams.ExeclDataHeader);
    
                //合并行的数据
                var mergeRowArr = row[eParams.NonMergeColumnCode] == DBNull.Value ? new string[0] : row[eParams.NonMergeColumnCode].ToString().Split(',');
    
                //重新设置当前行索引
                CurrentRowIndex = mergeRowArr.Length == 0 ? CurrentRowIndex + 1 : CurrentRowIndex + mergeRowArr.Length;
    
                for (var j = 0; j < eParams.ExeclDataHeader.Count; j++)
                {
                    var head = eParams.ExeclDataHeader[j];
    
                    var obj = row[head.ColumnCode] == DBNull.Value ? "" : row[head.ColumnCode];
    
                    //需要合并
                    if (mergeRowArr.Length >= 1)
                    {
                        if (j != nonMergeColumnIndex)
                        {
                            //合并
                            sheet.Cells.Merge(oldCurrentRowIndex, j, mergeRowArr.Length, 1);
    
                            if (j == imageColumnIndex)
                            {
                                if (!string.IsNullOrWhiteSpace(obj.ToString()))
                                {
                                    var ms = GetMemoryStream(obj.ToString());
                                    if (ms != null)
                                    {
                                        sheet.Cells.SetRowHeight(oldCurrentRowIndex, 45);
                                        int index = sheet.Pictures.Add(oldCurrentRowIndex, j, ms, 100, 100);
                                        SetImagePosition(sheet, index);
                                    }
                                }
                                SetCellStyle(sheet, style, oldCurrentRowIndex, j);
                            }
                            else
                            {
                                //赋值
                                sheet.Cells[oldCurrentRowIndex, j].PutValue(obj);
    
                                for (var k = 0; k < mergeRowArr.Length; k++)
                                {
                                    SetCellStyle(sheet, style, oldCurrentRowIndex + k, j);
                                }
                            }
                        }
                        else
                        {
                            for (var k = 0; k < mergeRowArr.Length; k++)
                            {
                                sheet.Cells[oldCurrentRowIndex + k, j].PutValue(mergeRowArr[k]);
                                SetCellStyle(sheet, style, oldCurrentRowIndex + k, j);
                            }
                        }
                    }
                    else
                    {
                        if (j == imageColumnIndex)
                        {
                            var ms = GetMemoryStream(obj.ToString());
                            if (ms != null)
                            {
                                sheet.Cells.SetRowHeight(oldCurrentRowIndex, 45);
                                int index = sheet.Pictures.Add(oldCurrentRowIndex, j, ms);
                                SetImagePosition(sheet, index);
                            }
    
                        }
                        else
                        {
                            sheet.Cells[oldCurrentRowIndex, j].PutValue(obj);
                        }
    
                        SetCellStyle(sheet, style, oldCurrentRowIndex, j);
                    }
                }
            }
    
            private void SetCellStyle(Worksheet sheet, Style style, int k, int j)
            {
                sheet.Cells[k, j].SetStyle(style);
            }
    
            private void SetImagePosition(Worksheet sheet, int index)
            {
                Aspose.Cells.Drawing.Picture pic = sheet.Pictures[index];
                pic.Left = 6;
                pic.Top = 2;
            }
    
            private void DefineStyle(Workbook workbook)
            {
                Style style;
                int styleIndex = workbook.Styles.Add();
                style = workbook.Styles[styleIndex];
                style.Font.Size = 25;
                style.Font.IsBold = true;
                style.HorizontalAlignment = TextAlignmentType.Center;
                style.Borders[BorderType.LeftBorder].Color = Color.Black;
                style.Borders[BorderType.LeftBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.RightBorder].Color = Color.Black;
                style.Borders[BorderType.RightBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.TopBorder].Color = Color.Black;
                style.Borders[BorderType.TopBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.BottomBorder].Color = Color.Black;
                style.Borders[BorderType.BottomBorder].LineStyle = CellBorderType.Thin;
                style.Name = "Font25Center";
    
                styleIndex = workbook.Styles.Add();
                style = workbook.Styles[styleIndex];
                style.Font.IsBold = true;
                style.HorizontalAlignment = TextAlignmentType.Center;
                style.Borders[BorderType.LeftBorder].Color = Color.Black;
                style.Borders[BorderType.LeftBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.RightBorder].Color = Color.Black;
                style.Borders[BorderType.RightBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.TopBorder].Color = Color.Black;
                style.Borders[BorderType.TopBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.BottomBorder].Color = Color.Black;
                style.Borders[BorderType.BottomBorder].LineStyle = CellBorderType.Thin;
                style.Name = "FontTitleCenter";
    
                styleIndex = workbook.Styles.Add();
                style = workbook.Styles[styleIndex];
                style.HorizontalAlignment = TextAlignmentType.Center;
                style.IsTextWrapped = true;
                style.Borders[BorderType.LeftBorder].Color = Color.Black;
                style.Borders[BorderType.LeftBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.RightBorder].Color = Color.Black;
                style.Borders[BorderType.RightBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.TopBorder].Color = Color.Black;
                style.Borders[BorderType.TopBorder].LineStyle = CellBorderType.Thin;
                style.Borders[BorderType.BottomBorder].Color = Color.Black;
                style.Borders[BorderType.BottomBorder].LineStyle = CellBorderType.Thin;
                style.Name = "FontCenter";
    
            }
    
            #region 辅助方法
    
            private int GetColumnIndex(string columnCode, IList<DataHeader> ExeclDataHeader)
            {
                var item = ExeclDataHeader.FirstOrDefault(w => w.ColumnCode == columnCode);
    
                return ExeclDataHeader.IndexOf(item);
            }
    
            private MemoryStream GetMemoryStream(string url)
            {
                try
                {
                    WebClient wc = new WebClient();
                    byte[] bytes = wc.DownloadData(url);
                    return new MemoryStream(bytes);
                }
                catch
                {
                    return null;
                }
            }
    
            #endregion
    
            #region 私有属性
    
            private int CurrentRowIndex { set; get; } 
    
            #endregion
        }
    

         调用代码如下:

          var data = GetExportProductInfo(querymodel).Data; //这里是datatable
                
                if (data.Rows.Count == 0)
                    return null;
    
                var exporterParams = new ExporterParams();
                exporterParams.ExeclDataHeader = new List<DataHeader>() { 
                    new DataHeader { DisplayName = "样版编号", ColumnCode = "SampleCode", ColumnWidth = 20 },
                    new DataHeader { DisplayName = "图片", ColumnCode = "SmallPicStyle",  ColumnWidth = 8 },
                    new DataHeader { DisplayName = "颜色", ColumnCode = "ColorName", ColumnWidth = 15 },
                };
    
                exporterParams.DocumentFileName = filePath;
                exporterParams.ExeclDataBody = data;
                exporterParams.NonMergeColumnCode = "ColorName";
                exporterParams.ImageColumnCode = "SmallPicStyle";
                exporterParams.ExeclTitle = "产品资料列表";
    
                IExeclDataExporter exporter = new ExeclDataExporter();
                exporter.DataExport(exporterParams);
    

          你们看了上面的代码是不是觉得很简单啊,呵呵,个人觉得吧,在合并单元格的计算逻辑需要注意一下,其他的都是搬砖的活,如果有什么疑问可以给我留言,写的不是很好请勿见怪。

      

  • 相关阅读:
    严格模式
    排序,求最大值最小值
    原型继承
    android 系统
    BASE64Decoder
    jstl
    list  遍历
    2015GitWebRTC编译实录9
    2015GitWebRTC编译实录8
    2015GitWebRTC编译实录7
  • 原文地址:https://www.cnblogs.com/wucj/p/3071633.html
Copyright © 2020-2023  润新知