基於NPOI封裝匯出Excel方法

沈威發表於2023-02-21

背景:

  在工作中我們有一個很常見的業務場景:匯出列表的資料,生成Excel,而使用NPOI生成Excel我們也會遇到一個問題,每遇到一個不同的類匯出時都要生成不同的表頭,行,列,但其實裡面大部分程式碼都是冗餘的,所以這時我就想到了一個點子,透過泛型和反射整一個通用的匯出方法.

匯出思路:

  其實這個業務場景的原理很簡單,首先我們需要查出資料並且將資料生成Excel檔案再透過IO流儲存在我們伺服器中,最後再將完整的連結地址返回給前端,前端訪問就直接下載下來了,還有一個問題則是解決那些冗餘程式碼,這裡就是我們上面提到的可以透過泛型和反射封裝一個通用的匯出方法或者整一個IEnumber<T>的擴充套件方法.

環境:

  程式碼環境使用的是.Net 6.0,

  Nuget包: 

 

 

實現:

  第一步,我們需要寫一個泛型獲取到泛型所有的欄位名稱和值的方法,用於生成表頭,行,列做鋪墊,程式碼如下:

  /// <summary>
        /// 獲取物件屬性名稱和值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public IEnumerable<KeyValue> GetProperties<T>(T t)
        {
            var result = new List<KeyValue>();
            System.Reflection.PropertyInfo[] properties = t.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            foreach (System.Reflection.PropertyInfo item in properties)
            {
                string name = item.Name; //名稱
                object value = item?.GetValue(t, null) ?? string.Empty;  ////if (item.PropertyType.IsValueType || item.PropertyType.Name.StartsWith("String"))
                //{
                result.Add(new KeyValue() { Key = item.Name, Value = item.GetValue(t, null) });
                //}
            }
            return result;
        }

  第二步,封裝一個匯出Excel檔案的方法,透過List<T>解決冗餘的問題,並透過不同的型別生成不同的Excel並且透過IO流存入伺服器中

 /// <summary>
        /// 通用匯出
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entitys"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public string ExportExcel<T>(IEnumerable<T> entitys, string fileName)
        {
            if (entitys == null || !entitys.Any()) return "無資料";
            XSSFWorkbook workBook = new XSSFWorkbook();
            ISheet sheet1 = workBook.CreateSheet("Sheet1");
            {
                var properties1 = GetProperties(entitys.ToList()[0]);
                //建立表頭
                var row = sheet1.CreateRow(0);
                for (var i = 0; i < properties1.Count(); i++)
                {
                    var cell = row.CreateCell(i);
                    cell.SetCellValue(properties1.ToList()[i].Key);
                }
            }
            //生成資料
            int index = 1;
            foreach (var entity in entitys)
            {
                var properties = GetProperties(entity);//獲取類中欄位的名稱和值
                var row = sheet1.CreateRow(index);
                var list = properties.ToList();
                for (var i = 0; i < properties.Count(); i++)
                {
                    var cell = row.CreateCell(i);
                    //var itemValue = list.FirstOrDefault(d => d.Key == heads[i]);
                    cell.SetCellValue(list[i].Value?.ToString() ?? string.Empty);
                }
                index++;
            }
            string defaultPath = System.IO.Directory.GetCurrentDirectory() + "/wwwroot/upload/file";
            if (!System.IO.Directory.Exists(defaultPath))
            {
                System.IO.Directory.CreateDirectory(defaultPath);//不存在就建立資料夾
            }
            //建立檔案 
            var file = new FileStream(defaultPath + "/" + fileName, FileMode.Create);
            workBook.Write(file);
            file.Close();
            return "upload/file/" + fileName;
        }

結尾:

  需要注意的是,生成的表頭,為類欄位的名稱,匯出的Dto欄位名稱可以寫成中文的,如果不想在程式碼中出現中文,可以再加一個List<string> heads//表頭的引數,更改掉生成表頭那段程式碼.

  最後希望這篇文章可以幫到你哦,文中有不足的地方也歡迎指正嘻嘻

相關文章