首页 > 其他分享 >基于DotNetCoreNPOI封装特性通用导出excel

基于DotNetCoreNPOI封装特性通用导出excel

时间:2023-04-18 10:36:20浏览次数:28  
标签:封装 string thisValue excel static typeof var DotNetCoreNPOI public

基于DotNetCoreNPOI封装特性通用导出excel

目前根据项目中的要求,支持列名定义,列索引排序,行合并单元格,EXCEL单元格的格式也是随着数据的类型做对应的调整。

效果图:

img

调用方式

可以看到时非常容易的能够导出数据,实际调用可能就三四句话

            // 你的需要导出的数据集合,这里的DownloadResponse就是你自己的数据集合
            List<DownloadResponse> dataList = GetDownloadList(data);
 
            // 导出逻辑
            var workbook = new XSSFWorkbook();
            var sheet = workbook.CreateSheet("Sheet1");
            sheet.SetValue(PropertyHelper.GetPropertyGetters(dataList), workbook);
 
            string path = Path.Combine(@"D:\", $"{Guid.NewGuid()}.xlsx");
            // 输出 Exce 文件
            using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write))
            {
                workbook.Write(fs);
            }
 public class DownloadResponse
    {
        /// <summary>
        /// 第一个参数:列名
        /// 第二个参数:索引(顺序)
        /// 第三个参数:是否合并单元格
        /// 后期可以添加一些样式,比如宽度,颜色等,暂时先这样吧
        /// </summary>
        [Excel("Customs Area", 0, true)]
        public string? CustomsArea { get; set; }
        [Excel("Vender", 1, true)]
        public string? VendorCode { get; set; }
    }

实现代码

   public static class PropertyHelper
    {
        /// <summary>
        /// 获取RemarkAttribute的值,并按index正序排序。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataList"></param>
        /// <returns></returns>
        public static Dictionary<int, List<PropertyGetterInfo>> GetPropertyGetters<T>(List<T> dataList)
        {
            var propertyGetters = GetExcelPropertyGetters<T>();

            var values = new Dictionary<int, List<PropertyGetterInfo>>();

            int rowIndex = 0;
            foreach (var response in dataList)
            {
                foreach (var getter in propertyGetters)
                {
                    string propertyName = getter.Key;
                    var attr = getter.Value.Attribute;

                    if (attr != null)
                    {
                        var value = getter.Value.Getter(response) as PropertyGetterInfo;
                        if (!values.TryGetValue(rowIndex, out var list))
                        {
                            list = new List<PropertyGetterInfo>();
                        }
                        list.Add(value);
                        values[rowIndex] = list;
                    }
                }
                rowIndex++;
            }
            return values;
        }

        /// <summary>
        /// 获取ExcelAttribute的值。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Dictionary<string, PropertyGetterInfo<T>> GetExcelPropertyGetters<T>()
        {
            var result = new Dictionary<string, PropertyGetterInfo<T>>();
            var properties = (from property in typeof(T).GetProperties()
                                  //where Attribute.IsDefined(property, typeof(RemarkAttribute))
                              orderby ((ExcelAttribute)property
                                        .GetCustomAttributes(typeof(ExcelAttribute), false)
                                        .Single()).Index
                              select property).ToArray();
            foreach (var prop in properties)
            {
                var attr = prop.GetCustomAttribute<ExcelAttribute>();
                if (attr != null)
                {
                    var getter = CreateGetter<T>(prop);
                    result[prop.Name] = new PropertyGetterInfo<T>
                    {
                        Attribute = attr,
                        Getter = getter
                    };
                }
            }
            return result;
        }
        private static Func<T, PropertyGetterInfo> CreateGetter<T>(PropertyInfo prop)
        {
            var instance = Expression.Parameter(typeof(T), "instance");
            var propertyAccess = Expression.Property(instance, prop);
            var castToObject = Expression.Convert(propertyAccess, typeof(object));
            var lambdaBody = Expression.MemberInit(
                Expression.New(typeof(PropertyGetterInfo)),
                Expression.Bind(
                    typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.Description)),
                    Expression.Constant(prop.GetCustomAttribute<ExcelAttribute>()?.Description ?? string.Empty)
                ),
                Expression.Bind(
                    typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.Index)),
                    Expression.Constant(prop.GetCustomAttribute<ExcelAttribute>()?.Index ?? 0)
                ),
                Expression.Bind(
                    typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.IsMerge)),
                    Expression.Constant(prop.GetCustomAttribute<ExcelAttribute>()?.IsMerge ?? false)
                ),
                Expression.Bind(
                    typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.Value)),
                    Expression.TypeAs(castToObject, typeof(object))
                ),
                Expression.Bind(
                    typeof(PropertyGetterInfo).GetProperty(nameof(PropertyGetterInfo.ValueType)),
                    Expression.Constant(prop.PropertyType.FullName)
                )
            );
            var lambda = Expression.Lambda<Func<T, PropertyGetterInfo>>(lambdaBody, instance);
            return lambda.Compile();
        }
    }

    public class PropertyGetterInfo
    {
        public string Description { get; set; }
        public int Index { get; set; }
        public bool IsMerge { get; set; }
        public object? Value { get; set; }
        public string ValueType { get; set; }
    }
    public class PropertyGetterInfo<T>
    {
        public ExcelAttribute? Attribute { get; set; }
        public Func<T, object?> Getter { get; set; }
    }

     public class ExcelAttribute : Attribute
    {
        /// <summary>
        /// 列描述
        /// </summary>
        private string _description;
        /// <summary>
        /// 列索引
        /// </summary>
        private int _index;
        /// <summary>
        /// 是否合并
        /// </summary>
        private bool _isMerge;
        public ExcelAttribute(string desc)
        {
            _description = desc;
        }
        public ExcelAttribute(string desc, int index)
        {
            _description = desc;
            _index = index;
        }
        public ExcelAttribute(string desc, int index, bool isMerge)
        {
            _description = desc;
            _index = index;
            _isMerge = isMerge;
        }
        public string Description
        {
            get
            {
                return _description;
            }
        }
        public int Index
        {
            get
            {
                return _index;
            }
        }
        public bool IsMerge
        {
            get
            {
                return _isMerge;
            }
        }
    }

  public static class ExcelHelper
    {
        static readonly string? _intType = typeof(int).FullName;
        static readonly string? _intNullType = typeof(int?).FullName;
        static readonly string? _longType = typeof(long).FullName;
        static readonly string? _longNullType = typeof(long?).FullName;
        static readonly string? _doubleType = typeof(double).FullName;
        static readonly string? _doubleNullType = typeof(double?).FullName;
        static readonly string? _decimalType = typeof(decimal).FullName;
        static readonly string? _decimalNullType = typeof(decimal?).FullName;
        static readonly string? _stringType = typeof(string).FullName;
        static readonly string? _dateTimeType = typeof(DateTime).FullName;
        static readonly string? _dateTimeNullType = typeof(DateTime?).FullName;
        static readonly string? _boolType = typeof(bool).FullName;
        static readonly string? _boolNullType = typeof(bool?).FullName;
        static readonly string? _guidType = typeof(Guid).FullName;
        static readonly string? _guidNullType = typeof(Guid?).FullName;

        public static void SetValue(this ISheet sheet, Dictionary<int, List<PropertyGetterInfo>> propertyGetters, XSSFWorkbook workbook)
        {
            bool isHead = true;
            int sheetRowIndex = 0;
            for (int i = 0; i < propertyGetters.Count; i++)
            {
                var item = propertyGetters[i];
                // 创建表头
                if (isHead)
                {
                    var headerRow = sheet.CreateRow(sheetRowIndex);
                    for (int j = 0; j < item.Count; j++)
                    {
                        headerRow.CreateCell(j).SetCellValue(item[j].Description);
                    }
                    isHead = false;
                    i--;
                    continue;
                }
                // 创建行
                sheetRowIndex++;
                var row = sheet.CreateRow(sheetRowIndex);
                for (int k = 0; k < item.Count; k++)
                {
                    var thisValue = item[k];
                    var cell = row.CreateCell(thisValue.Index);

                    if (thisValue.Value == null)
                    {
                        cell.SetCellType(CellType.String);
                        cell.SetCellValue(string.Empty);
                    }
                    if (thisValue.Value != null && thisValue.ValueType == _stringType)
                    {
                        cell.SetCellType(CellType.String);
                        cell.SetCellValue(thisValue.Value?.ToString());
                    }
                    // 数值类型
                    else if (thisValue.Value != null && (thisValue.ValueType == _intNullType
                       || thisValue.ValueType == _intType
                       || thisValue.ValueType == _decimalNullType
                       || thisValue.ValueType == _decimalType
                       || thisValue.ValueType == _longNullType
                       || thisValue.ValueType == _longType
                       || thisValue.ValueType == _doubleType
                       || thisValue.ValueType == _doubleNullType
                       ))
                    {
                        cell.SetCellType(CellType.Numeric);
                        double.TryParse(thisValue.Value?.ToString(), out double value);
                        cell.SetCellValue(value);
                    }
                    // 时间类型
                    else if (thisValue.Value != null && (thisValue.ValueType == _dateTimeNullType
                        || thisValue.ValueType == _dateTimeType))
                    {
                        DateTime.TryParse(thisValue.Value?.ToString(), out var value);
                        // 时间类型比较特殊,需要设置特定的单元格样式
                        var style = workbook.CreateCellStyle();
                        cell.SetCellValue(value.ToOADate());
                        style = workbook.CreateCellStyle();
                        style.DataFormat = HSSFDataFormat.GetBuiltinFormat("m/d/yy");
                        cell.CellStyle = style;
                    }
                    // bool类型
                    else if (thisValue.Value != null && (thisValue.ValueType == _boolNullType
                        || thisValue.ValueType == _boolType))
                    {
                        cell.SetCellType(CellType.Boolean);
                        bool.TryParse(thisValue.Value?.ToString(), out bool value);
                        cell.SetCellValue(value);
                    }
                    // 合并单元格
                    if (thisValue.IsMerge && thisValue.Value != null)
                    {
                        int nextIndex = i + 1;
                        if (nextIndex >= propertyGetters.Count)
                        {
                            continue;
                        }
                        var nextValue = propertyGetters[nextIndex];
                        var e = nextValue.FirstOrDefault(x => x.Description == thisValue.Description && (x.Value?.Equals(thisValue.Value) ?? false));
                        if (e != null)
                        {
                            // 合并当前行和下一行
                            var range = new CellRangeAddress(sheetRowIndex, sheetRowIndex + 1, e.Index, e.Index);
                            sheet.AddMergedRegion(range);
                        }
                    }
                }
            }
        }

    }

标签:封装,string,thisValue,excel,static,typeof,var,DotNetCoreNPOI,public
From: https://www.cnblogs.com/hanfan/p/17328666.html

相关文章

  • axios的二次封装(详解)
    一.首先让我们了解一下为什么要对axios进行二次封装?1,代码封装,重用性高,减少代码量,减低维护难度。2,统一处理一些常规的问题一劳永逸,如http错误。3,拦截请求和响应,提前对数据进行处理,如获取token,修改配置项。 安装axiosnpm下载npminstallaxios下载完成之后在main.js中全局......
  • 【进阶13】【自学笔记】Python logging模块封装
    一、定义  Pythonlogging模块是一个可以通过控制日志级别、输出位置等方式来实现记录日志的模块。logger对象的不同方法来记录不同级别的日志。  其中,debug()方法用于记录debug级别的日志,info()方法用于记录info级别的日志,warning()方法用于记录warning级别的日志,err......
  • ffmpeg可支持的编码器、解码器、封装格式、网络协议
    {ffmpeg可支持的编码器./configure--list-encodersffmpeg可支持的解码器./configure--list-decodersffmpeg可支持的封装格式./configure--list-muxersffmpeg可支持的解封装格式./configure--list-demuxersffmpeg可支持的网络协议./configure--list-protocols查看......
  • easysysprep4封装教程,自己封装系统
    本教程详细介绍如何使用easysysprep4进行封装系统的详细介绍。本教程分三个部分。easysysprep4封装教程上打开easysysprep4看到如下图这里只是显示了当前系统信息,以及easysysprep4设置的封装模式。我们点击“开始”进入下一步来到这里信息相对于图一信息量增加了很多,下面我们进行详......
  • 导出实体字段到Excel
    XrmToolBox中的AttributesFactory操作如下生成的Excel......
  • uni-app接口请求封装
    首先根目录下新建文件夹取名随意,这里我取名common(意为:常见的、共有的)然后新建request.js文件,贴入以下代码letserver_url='';//请求根路径(服务器地址)lettoken='';//token令牌//process.env.NODE_ENV==='development'?'http://192.168**:6002':'http://***/api&......
  • 线程池分批处理excel数据
    一、场景在开发excel处理数据时,因为数据库的卡顿,一次插入2000条数据速度可能需要1min左右,所以考虑使用线程池;每200个分组,有n组,就开(n+1)个线程去分批同时处理这些数据。二、依赖1.pom.xml<!--工具类hutool,java兵器库,用于读取excel--><dependency>......
  • tinymce封装成vue3组件
    封装成组件<scriptsetup>importEditorfrom'@tinymce/tinymce-vue'//引入tinymce开启本地模式import'tinymce/tinymce'//引入图标和主题等import'tinymce/themes/silver/theme'import'tinymce/icons/default/icons'import'tin......
  • react+ts+hook封装一个table分页组件(建议收藏,直接使用)
    前言大家好我是歌谣我是一名坚持写博客四年的博主最好的种树是十年前其次是现在,今天继续对antdesigntable的分页封装进行讲解封装准备(多看官网)jsx风格的api<><Table<User>columns={columns}dataSource={data}/>/*使用JSX风格的API*/<Table<User>data......
  • 在Excel中输入特殊字符   
    使用标准的计算机键盘你可以输入大约94种不同的字符,包括字母、数字和其它一些功能符号。但是我们在实际应用中会使用很多其它的字符,这些字符都不能通过标准的US键盘直接输入,例如标准字体Arial中就有大约200种不同的字符可以使用,包括英镑符号£,欧元符号€,版权符号©等。本文描述了......