NPOI+反射+自定义特性实现上传excel转List及验证

Posted betterlife

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NPOI+反射+自定义特性实现上传excel转List及验证相关的知识,希望对你有一定的参考价值。

1.自定义特性

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class PropertyDescriptionAttribute : Attribute
    {
        private bool _allownullorempty = true;
        public PropertyDescriptionAttribute() { }
        /// <summary>
        /// 是否允许为null或空值
        /// </summary>
        public bool AllowNullOrEmpty
        {
            get
            {
                return this._allownullorempty;
            }
            set
            {
                this._allownullorempty = value;
            }
        }
    }

2.定义类(假设是用户信息)

public class UploadUserModel
    {
        [PropertyDescription(AllowNullOrEmpty = false)]
        public string Name { get; set; }
        [PropertyDescription(AllowNullOrEmpty = false)]
        public string Phone { get; set; }
    }

自定义特定来标识这两个信息不能为空

3.实现

/// <summary>
/// PROPERTY_NAME数组:值与excel列一一对应
/// </summary>
private readonly string[] PROPERTY_NAME = { "Name", "Phone" };

private List<UploadUserModel> ExcelToList(HttpPostedFile excelFile)
        {
            IWorkbook workbook = null;
            ISheet sheet = null;
            int colCount = 0;
            List<UploadUserModel> users = new List<UploadUserModel>();
            if (excelFile.FileName.IndexOf(".xlsx") > 0)
            {
                workbook = new XSSFWorkbook(excelFile.InputStream);
            }
            else if (excelFile.FileName.IndexOf(".xls") > 0)
            {
                workbook = new HSSFWorkbook(excelFile.InputStream);
            }
            if (workbook != null)
            {
                sheet = workbook.GetSheetAt(0);
                if (sheet != null && sheet.LastRowNum > 0)
                {
                    colCount = sheet.GetRow(0).LastCellNum;//获取列数                    
                    //从第二行开始解析
                    for (int rowIndex = 1; rowIndex <= sheet.LastRowNum; rowIndex++)
                    {
                        var curRow = sheet.GetRow(rowIndex);//获取当前行                       
                        UploadUserModel user = new UploadUserModel();
                        Type cType = user.GetType();
                        //解析列
                        for (int colIndex = 0; colIndex < colCount; colIndex++)
                        {
                            var curCell = curRow.GetCell(colIndex);
                            if (curCell != null)
                            {
                                curCell.SetCellType(CellType.String);//把单元格设置成String类型,统一取值方式
                            }
                            //定义PROPERTY_NAME避免if判断
                            PropertyInfo propertyInfo = cType.GetProperty(PROPERTY_NAME[colIndex]);
                            //获取自定义特性
                            object[] customAttrs = propertyInfo.GetCustomAttributes(typeof(PropertyDescriptionAttribute), true);
                            if (customAttrs.Length > 0)
                            {
                                PropertyDescriptionAttribute attr = customAttrs[0] as PropertyDescriptionAttribute;
                                if (!attr.AllowNullOrEmpty)//属性值不能为空
                                {
                                    if (curCell == null)
                                    {
                                        throw new Exception("" + (rowIndex + 1).ToString() + "行有未填项,请填写后重新上传。");
                                    }
                                    else if (string.IsNullOrEmpty(curCell.StringCellValue))
                                    {
                                        throw new Exception("" + (rowIndex + 1).ToString() + "行有未填项,请填写后重新上传。");
                                    }
                                }
                                object cellValue = null;
                                if (curCell == null)
                                {
                                    cellValue = "";
                                }
                                else
                                {
                                    cellValue = curCell.StringCellValue;
                                }
                                if (!propertyInfo.PropertyType.IsGenericType)
                                {
                                    //非泛型
                                    propertyInfo.SetValue(user, curCell == null ? null : Convert.ChangeType(cellValue, propertyInfo.PropertyType), null);
                                }
                                else
                                {
                                    //泛型Nullable<>
                                    Type genericTypeDefinition = propertyInfo.PropertyType.GetGenericTypeDefinition();
                                    if (genericTypeDefinition == typeof(Nullable<>))
                                    {
                                        propertyInfo.SetValue(user, curCell == null ? null : Convert.ChangeType(cellValue, Nullable.GetUnderlyingType(propertyInfo.PropertyType)), null);
                                    }
                                }
                            }                            
                        }
                        users.Add(user);
                    }
                }
            }
            else
            {
                throw new Exception("Excel解析异常");
            }
            foreach (var item in users)
            {
                if (!checkPhoneGS(item.Phone))
                {
                    throw new Exception("手机号格式不正确:"+ item.Phone);
                }
            }
            return users;
        }

不要看着麻烦,核心代码很简单。用反射和定义PROPERTY_NAME数组是为了代码重用。最后那段泛型、非泛型判断可以删除,估计一般用不到

以上是关于NPOI+反射+自定义特性实现上传excel转List及验证的主要内容,如果未能解决你的问题,请参考以下文章

JS异步上传Excel 并使用NPOI进行读写操作

npoi2.3+泛型+反射 根据配置统一解析excel数据到实体的基础方法

NPOI DataTable转Excel ,Excel转DataTable

转.NET NPOI操作Excel常用函数

NPOI 入门--上传excel文件并解析

反射+自定义注解---实现Excel数据列属性和JavaBean属性的自动映射