消防站文档解析
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
15 KiB

3 years ago
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<T> ParseExcel<T>(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<T>(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<TType> ParseSheet<TType>(IWorkbook workBook, ISheet sheet)
{
var type = typeof(TType);
var result = new List<object>();
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, object> { { 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<TType>().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<HeaderColumnInfo> GetColumnInfos(List<TableColumnInfo> tableColumnInfos)
{
var result = new List<HeaderColumnInfo>();
tableColumnInfos.ForEach(c =>
{
var columnInfos = GetColumnInfos(c, 0);
result.AddRange(columnInfos);
});
return result;
}
private List<HeaderColumnInfo> GetColumnInfos(TableColumnInfo tableColumnInfo, int baseSort)
{
var result = new List<HeaderColumnInfo>();
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<TableHeaderAttribute> 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<TableColumnInfo> GetTableColumns(Type type)
{
var result = new List<TableColumnInfo>();
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<TableColumnInfo>() };
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<HeaderColumnInfo>, List<ImportDtoInfo>> 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<HeaderColumnInfo>();
var childDtoAttrs = new List<ImportDtoInfo>();
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<HeaderColumnInfo>, List<ImportDtoInfo>>(columnProperties, childDtoAttrs);
}
}
}