using Infrastructure.Abstructions; using Infrastructure.Excel.Attributes; using Microsoft.Extensions.Logging; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Infrastructure.Excel { public class Parser:ITransientDependency,IParser { public IWorkbook ReadExcel(string path) { if (!File.Exists(path)) { throw new Exception("该文件不存在"); } IWorkbook workBook = null; using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { try { var fileType = Path.GetExtension(path); if (fileType == ".xlsx") { //2007以上版本 workBook = new XSSFWorkbook(stream); } else if (fileType == ".xls") { //2007一下版本 workBook = new HSSFWorkbook(stream); } else { throw new Exception("非Excel文件不可解析"); } } catch (Exception e) { throw e; } } return workBook; } public List ParseExcel(IWorkbook workbook) where T : class, new() { var type = typeof(T); var sheetName = GetSheetName(type); var sheet = workbook.GetSheet(sheetName); if (sheet == null) { throw new Exception($"该Excel表格没有名为{sheetName}的sheet"); } var result = ParseSheet(workbook, sheet); return result; } public IWorkbook BuildWorkbook(Type type) { var workbook = new XSSFWorkbook(); BuildSheet(type, workbook); return workbook; } public ISheet BuildSheet(Type type, IWorkbook book) { var sheetName = GetSheetName(type); var tableColumns = GetTableColumns(type); var sheet = book.CreateSheet(sheetName); var depth = tableColumns.Max(c => c.Depth); var firstRow = sheet.CreateRow(0); var cellIndex = 0; foreach (var columnInfo in tableColumns) { SetTableColumns(sheet, firstRow, columnInfo, ref cellIndex); } return sheet; } private void SetTableColumns(ISheet sheet, IRow row, TableColumnInfo columnInfo, ref int cellIndex) { var cell = row.CreateCell(cellIndex++); cell.SetCellValue(columnInfo.Attribute.Name); if (columnInfo.ChildHeaderInfos != null && columnInfo.ChildHeaderInfos.Any()) { var nextRow = sheet.CreateRow(row.RowNum++); foreach (var childColumnInfo in columnInfo.ChildHeaderInfos) { SetTableColumns(sheet, nextRow, childColumnInfo, ref cellIndex); } } } private List ParseSheet(IWorkbook workBook, ISheet sheet) { var type = typeof(TType); var result = new List(); var tableHeaders = GetTableHeaders(type); var tableColumns = GetTableColumns(type); var depth = tableHeaders.Count + tableColumns.Max(c => c.Depth); var columnInfos = GetColumnInfos(tableColumns); var rowCount = sheet.LastRowNum; var cellCount = sheet.GetRow(depth)?.LastCellNum; if (!cellCount.HasValue) { throw new Exception("该Excel文档没有数据"); } for (var i = depth; i <= rowCount; i++) { var rootInstance = System.Activator.CreateInstance(type); var row = sheet.GetRow(i); var instanceDict = new Dictionary { { type, rootInstance } }; bool allBlank = true; for (int j = 0; j < cellCount; j++) { var cell = row.GetCell(j); if (cell == null || cell.CellType == CellType.Blank) { continue; } allBlank = false; var columnInfo = columnInfos[j]; object instance = null; if (!instanceDict.ContainsKey(columnInfo.Property.ReflectedType)) { instance = System.Activator.CreateInstance(columnInfo.Property.ReflectedType); instanceDict.Add(columnInfo.Property.ReflectedType, instance); } else { instance = instanceDict[columnInfo.Property.ReflectedType]; } var baseType = Nullable.GetUnderlyingType(columnInfo.Property.PropertyType); baseType = baseType == null ? columnInfo.Property.PropertyType : baseType; try { if (cell.CellType == CellType.Numeric && DateUtil.IsValidExcelDate(cell.NumericCellValue) && DateUtil.IsCellDateFormatted(cell))//日期类型 { var value = cell.DateCellValue; columnInfo.Property.SetValue(instance, Convert.ChangeType(value, baseType), null); } else { if (!string.IsNullOrEmpty(cell.ToString())) { switch (cell.CellType) { case CellType.String: columnInfo.Property.SetValue(instance, Convert.ChangeType(cell.StringCellValue, baseType), null); break; case CellType.Boolean: columnInfo.Property.SetValue(instance, Convert.ChangeType(cell.BooleanCellValue, baseType), null); break; case CellType.Numeric: { columnInfo.Property.SetValue(instance, DateUtil.IsCellDateFormatted(cell) ? Convert.ChangeType(cell.DateCellValue, baseType) : Convert.ChangeType(cell.NumericCellValue, baseType), null); break; } case CellType.Blank: columnInfo.Property.SetValue(instance, Convert.ChangeType(cell.ToString().Trim(), baseType), null); break; default: throw new Exception("不支持的单元格式"); } } } } catch (Exception e) { throw e; } } if (allBlank) { continue; } var baseTypePropertites = type.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public).ToList(); foreach (var property in baseTypePropertites) { if (instanceDict.ContainsKey(property.PropertyType)) { var subInstance = instanceDict[property.PropertyType]; property.SetValue(rootInstance, subInstance); } } result.Add(rootInstance); } return result.OfType().ToList(); } public string GetSheetName(Type type) { var importAttr = type.GetCustomAttributes(typeof(TableDtoAttribute), false).FirstOrDefault(); if (importAttr == null) { throw new Exception("非法类型,请检查该类型是否有Importable特性"); } var sheetName = ((TableDtoAttribute)importAttr).Name; return sheetName; } private List GetColumnInfos(List tableColumnInfos) { var result = new List(); tableColumnInfos.ForEach(c => { var columnInfos = GetColumnInfos(c, 0); result.AddRange(columnInfos); }); return result; } private List GetColumnInfos(TableColumnInfo tableColumnInfo, int baseSort) { var result = new List(); if (tableColumnInfo.ChildHeaderInfos != null && tableColumnInfo.ChildHeaderInfos.Any()) { var children = tableColumnInfo.ChildHeaderInfos.OrderBy(info => info.Attribute.Sort).ToList(); children.ForEach(child => { var childColumnInfos = GetColumnInfos(child, tableColumnInfo.Attribute.Sort); result.AddRange(childColumnInfos); }); } else { var columnInfo = new HeaderColumnInfo { Attribute = tableColumnInfo.Attribute, Property = tableColumnInfo.Property }; result.Add(columnInfo); } return result; } private List GetTableHeaders(Type type) { var headerAttrObjs = type.GetCustomAttributes(typeof(TableHeaderAttribute), true).ToList(); var headerAttrs = from obj in headerAttrObjs select (TableHeaderAttribute)obj; return headerAttrs.ToList(); } private List GetTableColumns(Type type) { var result = new List(); var properties = type.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public).ToList(); if (properties == null || !properties.Any()) { throw new Exception("该类型没有公共属性供生成Excel"); } foreach (var property in properties) { var columnAttrObj = property.GetCustomAttributes(typeof(ExcelColumnAttribute), true).FirstOrDefault(); if (columnAttrObj != null) { var header = new TableColumnInfo { Attribute = (ExcelColumnAttribute)columnAttrObj, Property = property, ChildHeaderInfos = new List() }; var propertyType = property.PropertyType; var columnDtoAttr = propertyType.GetCustomAttributes(typeof(TableColumnDtoAttribute), true).FirstOrDefault(); if (columnDtoAttr != null) { var childHeaders = GetTableColumns(propertyType); header.ChildHeaderInfos.AddRange(childHeaders); } result.Add(header); } else { var childImportDtoAttrObj = property.GetCustomAttributes(typeof(ChildImportDtoAttribute), true).FirstOrDefault(); if (childImportDtoAttrObj != null) { var childType = ((ChildImportDtoAttribute)childImportDtoAttrObj).DtoType; var childImportAttr = childType.GetCustomAttributes(typeof(TableDtoAttribute), false).FirstOrDefault(); if (childImportAttr == null) { throw new Exception("非法类型,请检查该类型是否有Importable特性"); } } } } return result.OrderBy(r => r.Attribute.Sort).ToList(); } private Tuple, List> GetImportPropertiesAndDtos(Type importType) { var properties = importType.GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public).ToList(); if (properties == null || !properties.Any()) { throw new Exception("该类型没有公共属性供生成Excel"); } var columnProperties = new List(); var childDtoAttrs = new List(); foreach (var property in properties) { var columnAttrObj = property.GetCustomAttributes(typeof(ExcelColumnAttribute), true).FirstOrDefault(); if (columnAttrObj != null) { var headerInfo = new HeaderColumnInfo { Attribute = (ExcelColumnAttribute)columnAttrObj, Property = property }; columnProperties.Add(headerInfo); } else { var childImportDtoAttrObj = property.GetCustomAttributes(typeof(ChildImportDtoAttribute), true).FirstOrDefault(); if (childImportDtoAttrObj != null) { var childType = ((ChildImportDtoAttribute)childImportDtoAttrObj).DtoType; var childImportAttr = childType.GetCustomAttributes(typeof(TableDtoAttribute), false).FirstOrDefault(); if (childImportAttr == null) { throw new Exception("非法类型,请检查该类型是否有Importable特性"); } childDtoAttrs.Add(new ImportDtoInfo { Attribute = (TableDtoAttribute)childImportAttr, Type = childType, Property = property }); } } } return new Tuple, List>(columnProperties, childDtoAttrs); } } }