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

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

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

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

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

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

  部门里面的架构组提供的导出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);

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

 

  

你可能感兴趣的:(exec)