Skip to content

Commit

Permalink
feat:Excel多Sheet 导入模板生成 dotnetcore#133
Browse files Browse the repository at this point in the history
  • Loading branch information
tanyongzheng committed Aug 7, 2020
1 parent 3f69649 commit da9b1fe
Show file tree
Hide file tree
Showing 3 changed files with 252 additions and 44 deletions.
98 changes: 94 additions & 4 deletions src/Magicodes.ExporterAndImporter.Excel/ExcelImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Magicodes.ExporterAndImporter.Core;
using Magicodes.ExporterAndImporter.Core.Models;
Expand All @@ -36,9 +37,39 @@ public class ExcelImporter : IExcelImporter
/// <exception cref="ArgumentException">文件名必须填写! - fileName</exception>
public Task<ExportFileInfo> GenerateTemplate<T>(string fileName) where T : class, new()
{
using (var importer = new ImportHelper<T>())
var isMultipleSheetType = false;
var tableType = typeof(T);
List<PropertyInfo> sheetPropertyList = new List<PropertyInfo>();
var sheetProperties = tableType.GetProperties();

for (var i = 0; i < sheetProperties.Length; i++)
{
return importer.GenerateTemplate(fileName);
var sheetProperty = sheetProperties[i];
var importerAttribute =
(sheetProperty.GetCustomAttributes(typeof(ExcelImporterAttribute), true) as ExcelImporterAttribute[])?.FirstOrDefault();
if (importerAttribute == null)
{
continue;
}
if (!string.IsNullOrEmpty(importerAttribute.SheetName))
{
isMultipleSheetType = true;
sheetPropertyList.Add(sheetProperty);
}
}

if (isMultipleSheetType)
{
using (var importer = new ImportMultipleSheetHelper(sheetPropertyList))
{
return importer.GenerateTemplate(fileName);
}
}
{
using (var importer = new ImportHelper<T>())
{
return importer.GenerateTemplate(fileName);
}
}
}

Expand All @@ -49,9 +80,40 @@ public class ExcelImporter : IExcelImporter
/// <returns>二进制字节</returns>
public Task<byte[]> GenerateTemplateBytes<T>() where T : class, new()
{
using (var importer = new ImportHelper<T>())
var isMultipleSheetType = false;
var tableType = typeof(T);
List<PropertyInfo> sheetPropertyList = new List<PropertyInfo>();
var sheetProperties = tableType.GetProperties();

for (var i = 0; i < sheetProperties.Length; i++)
{
var sheetProperty = sheetProperties[i];
var importerAttribute =
(sheetProperty.GetCustomAttributes(typeof(ExcelImporterAttribute), true) as ExcelImporterAttribute[])?.FirstOrDefault();
if (importerAttribute == null)
{
continue;
}
if (!string.IsNullOrEmpty(importerAttribute.SheetName))
{
isMultipleSheetType = true;
sheetPropertyList.Add(sheetProperty);
}
}

if (isMultipleSheetType)
{
return importer.GenerateTemplateByte();
using (var importer = new ImportMultipleSheetHelper(sheetPropertyList))
{
return importer.GenerateTemplateByte();
}
}
else
{
using (var importer = new ImportHelper<T>())
{
return importer.GenerateTemplateByte();
}
}
}

Expand Down Expand Up @@ -216,5 +278,33 @@ public async Task<Dictionary<string, ImportResult<TSheet>>> ImportSameSheets<T,
}
return resultList;
}


/// <summary>
/// 判断Dto类型是否为多Sheet类
/// </summary>
/// <typeparam name="T">Dto类型</typeparam>
/// <returns></returns>
private bool DtoTypeIsMultipleSheet<T>()
{
var tableType = typeof(T);
var sheetProperties = tableType.GetProperties();

for (var i = 0; i < sheetProperties.Length; i++)
{
var sheetProperty = sheetProperties[i];
var importerAttribute =
(sheetProperty.GetCustomAttributes(typeof(ExcelImporterAttribute), true) as ExcelImporterAttribute[])?.FirstOrDefault();
if (importerAttribute == null)
{
continue;
}
if (!string.IsNullOrEmpty(importerAttribute.SheetName))
{
return true;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public class ImportMultipleSheetHelper : IDisposable

private ExcelPackage _excelPackage;

private List<PropertyInfo> _sheetPropertyList;


private ImportMultipleSheetHelper()
{

Expand All @@ -45,6 +48,15 @@ public ImportMultipleSheetHelper(string filePath)
_excelStream = new FileStream(FilePath, FileMode.Open);
}

/// <summary>
/// Sheet属性信息列表
/// </summary>
/// <param name="sheetPropertyList"></param>
public ImportMultipleSheetHelper(List<PropertyInfo> sheetPropertyList)
{
_sheetPropertyList = sheetPropertyList;
}

/// <summary>
/// 导入全局设置
/// </summary>
Expand Down Expand Up @@ -464,53 +476,137 @@ protected virtual bool ParseImporterHeader()
}

/// <summary>
/// 构建Excel模板
/// 解析头部
/// </summary>
protected virtual void StructureExcel(ExcelPackage excelPackage)
/// <returns></returns>
/// <exception cref="ArgumentException">导入实体没有定义ImporterHeader属性</exception>
protected virtual bool ParseImporterHeader(Type sheetType)
{
var worksheet =
excelPackage.Workbook.Worksheets.Add(_importDataType.GetDisplayName() ??
ExcelImporterSettings.SheetName ?? "导入数据");
if (!ParseImporterHeader()) return;
ImporterHeaderInfos = new List<ImporterHeaderInfo>();
var objProperties = sheetType.GetProperties();
if (objProperties.Length == 0) return false;

//设置列头
for (var i = 0; i < ImporterHeaderInfos.Count; i++)
foreach (var propertyInfo in objProperties)
{
//忽略
if (ImporterHeaderInfos[i].Header.IsIgnore) continue;

worksheet.Cells[ExcelImporterSettings.HeaderRowIndex, i + 1].Value =
ImporterHeaderInfos[i].Header.Name;
if (!string.IsNullOrWhiteSpace(ImporterHeaderInfos[i].Header.Description))
worksheet.Cells[ExcelImporterSettings.HeaderRowIndex, i + 1].AddComment(
ImporterHeaderInfos[i].Header.Description,
ImporterHeaderInfos[i].Header.Author);
//如果必填,则列头标红sd
if (ImporterHeaderInfos[i].IsRequired)
worksheet.Cells[ExcelImporterSettings.HeaderRowIndex, i + 1].Style.Font.Color.SetColor(Color.Red);

if (ImporterHeaderInfos[i].MappingValues.Count > 0)
//TODO:简化并重构
//如果不设置,则自动使用默认定义
var importerHeaderAttribute =
(propertyInfo.GetCustomAttributes(typeof(ImporterHeaderAttribute), true) as
ImporterHeaderAttribute[])?.FirstOrDefault() ?? new ImporterHeaderAttribute
{
Name = propertyInfo.GetDisplayName() ?? propertyInfo.Name
};

if (string.IsNullOrWhiteSpace(importerHeaderAttribute.Name))
importerHeaderAttribute.Name = propertyInfo.GetDisplayName() ?? propertyInfo.Name;

//忽略字段处理
if (importerHeaderAttribute.IsIgnore) continue;

var colHeader = new ImporterHeaderInfo
{
IsRequired = propertyInfo.IsRequired(),
PropertyName = propertyInfo.Name,
Header = importerHeaderAttribute
};
ImporterHeaderInfos.Add(colHeader);

#region 处理值映射

var mappings = propertyInfo.GetAttributes<ValueMappingAttribute>().ToList();
foreach (var mappingAttribute in mappings.Where(mappingAttribute =>
!colHeader.MappingValues.ContainsKey(mappingAttribute.Text)))
colHeader.MappingValues.Add(mappingAttribute.Text, mappingAttribute.Value);

//如果存在自定义映射,则不会生成默认映射
if (mappings.Any()) continue;

//为bool类型生成默认映射
switch (propertyInfo.PropertyType.GetCSharpTypeName())
{
//针对枚举类型和Bool类型添加数据约束
var range = ExcelCellBase.GetAddress(ExcelImporterSettings.HeaderRowIndex + 1, i + 1,
ExcelPackage.MaxRows, i + 1);
var dataValidations = worksheet.DataValidations.AddListValidation(range);
foreach (var mappingValue in ImporterHeaderInfos[i].MappingValues)
dataValidations.Formula.Values.Add(mappingValue.Key);
case "Boolean":
case "Nullable<Boolean>":
{
if (!colHeader.MappingValues.ContainsKey("是")) colHeader.MappingValues.Add("是", true);
if (!colHeader.MappingValues.ContainsKey("否")) colHeader.MappingValues.Add("否", false);
break;
}
}

var type = propertyInfo.PropertyType;
var isNullable = type.IsNullable();
if (isNullable) type = type.GetNullableUnderlyingType();
//为枚举类型生成默认映射
if (type.IsEnum)
{
var values = type.GetEnumTextAndValues();
foreach (var value in values.Where(value => !colHeader.MappingValues.ContainsKey(value.Key)))
colHeader.MappingValues.Add(value.Key, value.Value);

if (isNullable)
if (!colHeader.MappingValues.ContainsKey(string.Empty))
colHeader.MappingValues.Add(string.Empty, null);
}

#endregion
}

worksheet.Cells.AutoFitColumns();
worksheet.Cells.Style.WrapText = true;
worksheet.Cells[worksheet.Dimension.Address].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
worksheet.Cells[worksheet.Dimension.Address].Style.VerticalAlignment = ExcelVerticalAlignment.Center;

worksheet.Cells[worksheet.Dimension.Address].Style.Border.Left.Style = ExcelBorderStyle.Thin;
worksheet.Cells[worksheet.Dimension.Address].Style.Border.Right.Style = ExcelBorderStyle.Thin;
worksheet.Cells[worksheet.Dimension.Address].Style.Border.Top.Style = ExcelBorderStyle.Thin;
worksheet.Cells[worksheet.Dimension.Address].Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
worksheet.Cells[worksheet.Dimension.Address].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells[worksheet.Dimension.Address].Style.Fill.BackgroundColor.SetColor(Color.DarkSeaGreen);
return true;
}
/// <summary>
/// 构建Excel模板
/// </summary>
protected virtual void StructureExcel(ExcelPackage excelPackage)
{
foreach (var sheetProperty in _sheetPropertyList)
{
var sheetType= sheetProperty.PropertyType;
var importerAttribute =
(sheetProperty.GetCustomAttributes(typeof(ExcelImporterAttribute), true) as ExcelImporterAttribute[])?.FirstOrDefault();

var worksheet =
excelPackage.Workbook.Worksheets.Add(importerAttribute.SheetName);
if (!ParseImporterHeader(sheetType)) return;

//设置列头
for (var i = 0; i < ImporterHeaderInfos.Count; i++)
{
//忽略
if (ImporterHeaderInfos[i].Header.IsIgnore) continue;

worksheet.Cells[importerAttribute.HeaderRowIndex, i + 1].Value =
ImporterHeaderInfos[i].Header.Name;
if (!string.IsNullOrWhiteSpace(ImporterHeaderInfos[i].Header.Description))
worksheet.Cells[importerAttribute.HeaderRowIndex, i + 1].AddComment(
ImporterHeaderInfos[i].Header.Description,
ImporterHeaderInfos[i].Header.Author);
//如果必填,则列头标红
if (ImporterHeaderInfos[i].IsRequired)
worksheet.Cells[importerAttribute.HeaderRowIndex, i + 1].Style.Font.Color.SetColor(Color.Red);

if (ImporterHeaderInfos[i].MappingValues.Count > 0)
{
//针对枚举类型和Bool类型添加数据约束
var range = ExcelCellBase.GetAddress(importerAttribute.HeaderRowIndex + 1, i + 1,
ExcelPackage.MaxRows, i + 1);
var dataValidations = worksheet.DataValidations.AddListValidation(range);
foreach (var mappingValue in ImporterHeaderInfos[i].MappingValues)
dataValidations.Formula.Values.Add(mappingValue.Key);
}
}

worksheet.Cells.AutoFitColumns();
worksheet.Cells.Style.WrapText = true;
worksheet.Cells[worksheet.Dimension.Address].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
worksheet.Cells[worksheet.Dimension.Address].Style.VerticalAlignment = ExcelVerticalAlignment.Center;

worksheet.Cells[worksheet.Dimension.Address].Style.Border.Left.Style = ExcelBorderStyle.Thin;
worksheet.Cells[worksheet.Dimension.Address].Style.Border.Right.Style = ExcelBorderStyle.Thin;
worksheet.Cells[worksheet.Dimension.Address].Style.Border.Top.Style = ExcelBorderStyle.Thin;
worksheet.Cells[worksheet.Dimension.Address].Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
worksheet.Cells[worksheet.Dimension.Address].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells[worksheet.Dimension.Address].Style.Fill.BackgroundColor.SetColor(Color.DarkSeaGreen);
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -110,5 +111,26 @@ public async Task ClassStudentInfoImporter_SaveLabelingError_Test()
_testOutputHelper.WriteLine($"保存标注错误Excel文件已生成,路径:{labelingErrorExcelPath}");
}
}


[Fact(DisplayName = "多Sheet导出模板")]
public async Task MultipleSheetGenerateTemplate_Test()
{
var Importer = new ExcelImporter();
var bytes1 = await Importer.GenerateTemplateBytes<ImportClassStudentDto>();
var str1 = Convert.ToBase64String(bytes1);
_testOutputHelper.WriteLine($"已导出多Sheet的Excel模板,Base64:{str1}");
var tempaltePath2 = Path.Combine(Directory.GetCurrentDirectory(), "TestFiles", "Import", "学生基础数据及缴费流水号模板导出.xlsx");
await Importer.GenerateTemplate<ImportStudentAndPaymentLogDto>(tempaltePath2);

if (File.Exists(tempaltePath2))
{
_testOutputHelper.WriteLine($"已导出Excel模板,路径:{tempaltePath2}");
}
//一个Sheet导出
var bytes3 = await Importer.GenerateTemplateBytes<ImportStudentDto>();
var str3 = Convert.ToBase64String(bytes3);
_testOutputHelper.WriteLine($"已导出单个Sheet的Excel模板,Base64:{str3}");
}
}
}

0 comments on commit da9b1fe

Please sign in to comment.