赞
踩
.net core 项目
可以从excel读取任何类型(T)的数据,只要T中的field的[Display(Name = "1233")]中的name==excel column header's name
引用的nuget包:
1.EPPlus.Core
2. System.ComponentModel.Annotations
//类定义
public
class
ExcelReadServiceAccordingDisplayAttr<T> : IExcelReadService<T>
where
T :
new
()
{
ILogBase _logger;
static
Dictionary<
string
, PropertyInfo> _displayAttrDic;
public
ExcelReadServiceAccordingDisplayAttr(ILogBase logBase)
{
_logger = logBase;
}
}
class ExcelReadServiceAccordingDisplayAttr<T>中方法:
private
List<T> GetData(
string
excelPath,
string
sheetName =
""
,
int
sheetIndex = 0)
{
try
{
FileInfo existingFile =
new
FileInfo(excelPath);
using
(ExcelPackage package =
new
ExcelPackage(existingFile))
{
ExcelWorksheet sheet = GetSheet(package, sheetName, sheetIndex);
if
(sheet ==
null
)
return
null
;
//获取不需要读取的column
List<
long
> excluedeColumns = GetExcludeCloumns(sheet);
//根据excelheader来获取type T数据对象的列字典
Dictionary<
int
, PropertyInfo> columnIndexDic = GetColumnIndexDicFromExcelHeader(sheet, excluedeColumns);
//读取excel数据,填充List<T>
List<T> result = GetDatesFromContent(sheet, columnIndexDic, excluedeColumns);
return
result;
}
}
catch
(Exception ex)
{
_logger.Error($
"get data from excel exception :{ex.ToString()},excel:{excelPath},sheetIndex:{sheetIndex},entityType:{typeof(T).FullName}"
);
throw
ex;
}
}
private
List<T> GetDateFromSheet(ExcelWorksheet sheet)
{
if
(sheet ==
null
)
return
null
;
List<
long
> excluedeColumns = GetExcludeCloumns(sheet);
//根据excelheader来获取type T数据对象的列字典
Dictionary<
int
, PropertyInfo> columnIndexDic = GetColumnIndexDicFromExcelHeader(sheet, excluedeColumns);
//读取excel数据,填充List<T>
List<T> result = GetDatesFromContent(sheet, columnIndexDic);
return
result;
}
private
List<T> GetData(
byte
[] excelContent,
string
sheetName =
""
,
int
sheetIndex = 0)
{
try
{
using
(Stream stream =
new
MemoryStream(excelContent))
{
using
(ExcelPackage package =
new
ExcelPackage(stream))
{
ExcelWorksheet sheet = GetSheet(package, sheetName, sheetIndex);
return
GetDateFromSheet(sheet);
}
}
}
catch
(Exception ex)
{
_logger.Error($
"get data from excel exception :{ex.ToString()},excelContent:{excelContent},sheetIndex:{sheetIndex},entityType:{typeof(T).FullName}"
);
throw
ex;
}
}
private
ExcelCheckResult CheckDate(
byte
[] excelContent,
string
sheetName =
""
,
int
sheetIndex = 0)
{
try
{
using
(Stream stream =
new
MemoryStream(excelContent))
{
using
(ExcelPackage package =
new
ExcelPackage(stream))
{
ExcelWorksheet sheet = GetSheet(package, sheetName, sheetIndex);
if
(sheet ==
null
)
return
null
;
List<
long
> excluedeColumns = GetExcludeCloumns(sheet);
//根据excelheader来获取type T数据对象的列字典
Dictionary<
int
, PropertyInfo> columnIndexDic = GetColumnIndexDicFromExcelHeader(sheet, excluedeColumns);
bool
formatResult=FormatSheet(
ref
sheet, columnIndexDic);
package.Save();
if
(!formatResult)
{
return
new
ExcelCheckResult() { CheckResult =
false
, CheckMsg =
"format error!"
};
}
return
CheckExcel(
ref
sheet, columnIndexDic);
}
}
}
catch
(Exception ex)
{
_logger.Error($
"get data from excel exception :{ex.ToString()},excelContent:{excelContent},sheetIndex:{sheetIndex},entityType:{typeof(T).FullName}"
);
throw
ex;
}
}
/// <summary>
/// 根据 DisplayAttribute 的 Description 来格式化sheet
/// </summary>
/// <param name="sheet"></param>
/// <param name="columnIndexDic"></param>
private
bool
FormatSheet(
ref
ExcelWorksheet sheet, Dictionary<
int
, PropertyInfo> columnIndexDic)
{
try
{
var
typeOfObject =
typeof
(T);
var
columnIndexDicForDisplayAttr =
new
Dictionary<
int
, DisplayAttribute>();
foreach
(
var
columnInfo
in
columnIndexDic)
{
int
columnKey = columnInfo.Key;
PropertyInfo columnProperty = columnInfo.Value;
var
attr = columnProperty.GetCustomAttribute(
typeof
(DisplayAttribute))
as
DisplayAttribute;
if
(attr !=
null
&& !
string
.IsNullOrEmpty(attr.Description))
{
var
originalFormat = sheet.Column(columnKey).Style.Numberformat.Format;
sheet.Column(columnKey).Style.Numberformat.Format = attr.Description;
_logger.Warn($
"change cloumn{columnKey} formate({ originalFormat}=>{attr.Description}):(class:{typeOfObject.FullName},property:{columnProperty.Name})"
);
}
}
return
true
;
}
catch
(Exception ex)
{
_logger.Error($
"excel Format error. columnIndexDic:{JsonConvert.SerializeObject(columnIndexDic.Keys)}"
, ex);
return
false
;
}
}
private
ExcelCheckResult CheckExcel(
ref
ExcelWorksheet sheet, Dictionary<
int
, PropertyInfo> columnIndexDic)
{
var
excelCheckResult =
new
ExcelCheckResult() {
CheckResult=
true
,
CheckMsg=
"Succeed!"
};
var
columnPropertyDic = columnIndexDic.Values.ToLookup(p=>p.Name).ToDictionary(kp => kp.Key, kp => kp.FirstOrDefault());
Dictionary<
string
, PropertyInfo> requiredPropertyDic= GetRequireDicFromType();
StringBuilder msg =
new
StringBuilder();
foreach
(
var
requiredProperty
in
requiredPropertyDic)
{
var
properName = requiredProperty.Key;
if
(!columnPropertyDic.ContainsKey(properName))
{
msg.AppendLine($
"{properName} is required!"
);
_logger.Warn($
"property:({properName}) is required ! columnIndexDic:{JsonConvert.SerializeObject(columnIndexDic.Keys)}"
);
}
}
if
(!
string
.IsNullOrEmpty(msg.ToString()))
{
excelCheckResult.CheckResult =
false
;
excelCheckResult.CheckMsg = msg.ToString();
}
return
excelCheckResult;
}
private
Dictionary<
string
, PropertyInfo> GetRequireDicFromType()
{
Type typeOfObject =
typeof
(T);
var
pds = typeOfObject.GetProperties();
if
(pds ==
null
)
return
null
;
var
propertyDic = pds.ToLookup(p => {
var
attr = p.GetCustomAttribute(
typeof
(RequiredAttribute))
as
RequiredAttribute;
if
(attr ==
null
)
return
""
;
return
p.Name;
}).ToDictionary(kp => kp.Key, kp => kp.FirstOrDefault());
if
(propertyDic ==
null
|| propertyDic.Count() == 0)
{
_logger.Warn($
"no RequireDic can get from class Type:{typeOfObject.FullName} "
);
}
else
{
propertyDic.Remove(
""
);
}
return
propertyDic;
}
private
List<
long
> GetExcludeCloumns(ExcelWorksheet sheet)
{
List<
long
> excludeCloumns =
new
List<
long
>();
if
(sheet.PivotTables ==
null
)
return
excludeCloumns;
//排除sheet中透视表的列
foreach
(
var
povotTable
in
sheet.PivotTables)
{
var
startCloumn = povotTable.Address.Start.Column;
var
endColumn= povotTable.Address.End.Column;
while
(startCloumn <= endColumn)
{
excludeCloumns.Add(startCloumn);
startCloumn++;
}
}
return
excludeCloumns;
}
private
ExcelWorksheet GetSheet(ExcelPackage package,
string
sheetName,
int
sheetIndex)
{
if
(package ==
null
|| package.Workbook ==
null
|| package.Workbook.Worksheets ==
null
|| package.Workbook.Worksheets.Count == 0)
return
null
;
ExcelWorksheets excelWorksheets = package.Workbook.Worksheets;
if
(!
string
.IsNullOrWhiteSpace(sheetName))
{
var
targetSheet = excelWorksheets.Where(s => s.Name.ToLower().Trim() == sheetName.ToLower());
if
(targetSheet ==
null
|| targetSheet.Count() == 0)
return
null
;
return
targetSheet.FirstOrDefault();
}
else
if
(sheetIndex > 0 && sheetIndex + 1 <= excelWorksheets.Count())
{
return
excelWorksheets[sheetIndex + 1];
}
else
{
return
excelWorksheets.FirstOrDefault();
}
}
private
Dictionary<
int
, PropertyInfo> GetColumnIndexDicFromExcelHeader(ExcelWorksheet sheet, List<
long
> excluedeColumns)
{
if
(_displayAttrDic ==
null
)
{
//获取 Dictionary<excel column Header text,DisplayAttribute>
_displayAttrDic = GetDisplayDicFromType(
typeof
(T));
}
Dictionary<
int
, PropertyInfo> displayOrderDic =
new
Dictionary<
int
, PropertyInfo>();
if
(sheet ==
null
)
return
displayOrderDic;
if
(_displayAttrDic ==
null
|| _displayAttrDic.Count == 0)
{
_logger.Warn($
"no _displayAttrDic can get ."
);
return
displayOrderDic;
}
//获取 Dictionary<column index,PropertyInfo of class T>
var
query1 = (
from
cell
in
sheet.Cells[1, 1, 1, sheet.Dimension.Columns]
where
!excluedeColumns.Contains(cell.Start.Column)
select
cell);
foreach
(
var
cell
in
query1)
{
var
columnName = cell.Value.ToString().ToLower().Trim();
if
(_displayAttrDic.ContainsKey(columnName))
{
var
propertyInfo = _displayAttrDic[columnName];
displayOrderDic.Add(cell.Start.Column, propertyInfo);
}
}
if
(displayOrderDic ==
null
|| displayOrderDic.Count() == 0)
{
_logger.Warn($
"no ColumnIndexDic can get from ExcelHeader. sheet:{sheet.Name},_displayAttrDic got no data"
);
}
return
displayOrderDic;
}
private
Dictionary<
string
,PropertyInfo> GetDisplayDicFromType(Type typeOfObject)
{
var
pds = typeOfObject.GetProperties();
if
(pds ==
null
)
return
null
;
//DisplayAttribute 中的Name==excel column Header
var
propertyDic = pds.ToLookup(p=> {
var
attr = p.GetCustomAttribute(
typeof
(DisplayAttribute))
as
DisplayAttribute;
if
(attr ==
null
)
return
""
;
return
attr.Name.ToLower().Trim();
}).ToDictionary(kp => kp.Key, kp=> kp.FirstOrDefault());
if
(propertyDic==
null
|| propertyDic.Count() == 0)
{
_logger.Warn($
"no DisplayDic can get from class Type:{typeOfObject.FullName} "
);
}
return
propertyDic;
}
private List<T> GetDatesFromContent(ExcelWorksheet sheet, Dictionary<int, PropertyInfo> columnIndexDic, List<long> excluedeColumns)
{
List<T> result = new List<T>();
//fill list form excel
Dictionary<string, Dictionary<string, object>> enumDic = new Dictionary<string, Dictionary<string, object>>();
var query2 = (from cell in sheet.Cells[2, 1, sheet.Dimension.Rows, sheet.Dimension.Columns] where !excluedeColumns.Contains(cell.Start.Column) select cell);
T temp = default(T);
foreach (var cell in query2)
{
if (cell.Start.Column == 1)
{
if (temp != null) result.Add(temp);
temp = (T)Activator.CreateInstance(typeof(T));
}
if (cell.Value == null || string.IsNullOrWhiteSpace(cell.Value.ToString())) continue;
SetValueAccordingEachCell(cell, temp, columnIndexDic, ref enumDic);
}
if (temp != null) result.Add(temp);
return result;
}
//according cell value to set T's property value
private void SetValueAccordingEachCell(ExcelRangeBase cell, T temp, Dictionary<int, PropertyInfo> columnIndexDic, ref Dictionary<string, Dictionary<string, object>> enumDic)
{
try
{
var columnIndex = cell.Start.Column;
if (columnIndexDic == null || columnIndexDic.Count() == 0)
{
_logger.Warn($"no column Index can get from cell(address:{cell.Start.Address} ,value:{cell.Value})");
return;
}
if (!columnIndexDic.ContainsKey(columnIndex))
{
_logger.Warn($"no column Index can get from cell(address:{cell.Start.Address} ,value:{cell.Value}),columnIndexDic:{JsonConvert.SerializeObject(columnIndexDic.Keys)}");
return;
}
var propertyInfo = columnIndexDic[columnIndex];
Type propertyType = propertyInfo.PropertyType;
if (propertyType.IsEnum)
{
Dictionary<string, object> enumDicTemp;
if (enumDic.ContainsKey(propertyType.FullName))
{
enumDicTemp = enumDic[propertyType.FullName];
}
else
{
enumDicTemp = GetEnumDicFromType(propertyType);
enumDic.Add(propertyType.FullName, enumDicTemp);
}
object enumValue = null;
if (enumDicTemp != null)
{
if (enumDicTemp.ContainsKey(cell.Value.ToString()))
{
enumValue = enumDicTemp[cell.Value.ToString()];
}
else
{
_logger.Warn($"no enum value can get from enum dictionary:{JsonConvert.SerializeObject(enumDicTemp.Keys)} , enum Type:{propertyType.FullName},cell (address:{cell.Start.Address},value:{cell.Value.ToString()})");
}
}
else
{
_logger.Warn($"no enum dictionary can get from enum Type:{propertyType.FullName} ");
}
if (enumValue != null)
{
propertyInfo.SetValue(temp, enumValue);
}
else
{
_logger.Warn($"no enum value can get for cell:{cell.Value} ");
}
return;
}
if (propertyType == typeof(decimal))
{
string cellV = cell.Value.ToString();
decimal multiply = 1;
if (cellV.Contains("%"))
{
multiply = 100;
cellV = cellV.Substring(0, cellV.IndexOf("%") + 1);
}
decimal tempV;
bool convertR = decimal.TryParse(cellV, out tempV);
if (convertR)
{
propertyInfo.SetValue(temp, tempV * multiply);
}
else
{
_logger.Warn($"no decimal value can get for cell:(address:{cell.Address},value:{cell.Value})");
}
return;
}
if (propertyType == typeof(int))
{
propertyInfo.SetValue(temp, Convert.ToInt32(cell.Value));
return;
}
if (propertyType == typeof(long))
{
propertyInfo.SetValue(temp, Convert.ToInt64(cell.Value));
return;
}
if (propertyType == typeof(DateTime))
{
propertyInfo.SetValue(temp, Convert.ToDateTime(cell.Value));
return;
}
if (propertyType == typeof(string))
{
propertyInfo.SetValue(temp, cell.Value.ToString());
return;
}
propertyInfo.SetValue(temp, cell.Value.ToString());
return;
}
catch(Exception ex)
{
_logger.Error($"no property value can set from cell:(address:{cell.Address},value:{cell.Value})");
throw ex;
}
}
// get Dictionary<enumn's display name==excel cell value,emumn value>
private Dictionary<string, object> GetEnumDicFromType(Type propertyType)
{
var result = new Dictionary<string, object>();
if (propertyType.IsEnum)
{
var enumValues = propertyType.GetEnumValues();
foreach (var value in enumValues)
{
MemberInfo memberInfo =
propertyType.GetMember(value.ToString()).First();
var descriptionAttribute =
memberInfo.GetCustomAttribute<DisplayAttribute>();
if (descriptionAttribute != null)
{
result.Add(descriptionAttribute.Name, value);
}
else
{
var enumString = Enum.GetName(propertyType, value);
result.Add(enumString, value);
}
}
if (result == null || result.Count() == 0)
{
_logger.Warn($"no EnumDic can get from enum Type:{propertyType.FullName} ");
}
}
return result;
}
相关辅助类:
enum class
public
enum
AdvertiseType:Int32
{
/// <summary>
/// Search
/// </summary>
[Display(Name =
"Search"
)]
Search = 1,
/// <summary>
/// Display
/// </summary>
[Display(Name =
"Display"
)]
Display = 2,
}
T class:
public
class
FinancialBillEntity
{
[Display(Name =
"类型"
)]
public
BussinessType AdvertiseType{
get
;
set
; }
[Display(Name =
"平台2343"
)]
public
string
AdvertisePlantform {
get
;
set
; }
[Display(Name =
"签约12312"
)]
public
string
PlantformSignEntity {
get
;
set
; }
}
应用:
//register interface
services.RegisterServiceR<ExcelReadServiceAccordingDisplayAttr<FinancialBillEntity>,IExcelReadService<FinancialBillEntity>>(lifeStyle);
//get interface instance
var
excelWriteService= services.GetInstance<IExcelWriteService<FinancialBillEntity>>();
//execute interface method
bool
result=_excelWriteService.WriteData(financeBills,cmdOptions.OutputFinanceBillExcelPath,cmdOptions.OutputFinanceBillSheetName);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。