From a5b2b0939362be61fb33587840b5c2aff66e01a7 Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 9 Oct 2024 15:13:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(exporter):=20=E5=A2=9E=E5=8A=A0=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=AF=BC=E5=85=A5=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ ....Abp.Exporter.Application.Contracts.csproj | 20 ++++ .../AbpExporterApplicationContractsModule.cs | 9 ++ .../Abp/Exporter/IExporterAppService.cs | 19 ++++ .../Abp/Exporter/IImporterAppService.cs | 17 +++ .../README.md | 103 ++++++++++++++++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ .../LINGYUN.Abp.Exporter.Application.csproj | 25 +++++ .../Exporter/AbpExporterApplicationModule.cs | 12 ++ .../Abp/Exporter/ExporterAppService.cs | 50 +++++++++ .../Abp/Exporter/ImporterAppService.cs | 47 ++++++++ .../LINGYUN.Abp.Exporter.Core/FodyWeavers.xml | 3 + .../LINGYUN.Abp.Exporter.Core/FodyWeavers.xsd | 30 +++++ .../LINGYUN.Abp.Exporter.Core.csproj | 30 +++++ .../Abp/Exporter/AbpExporterCoreModule.cs | 31 ++++++ .../Abp/Exporter/ExporterErrorCodes.cs | 9 ++ .../LINGYUN/Abp/Exporter/IExporterProvider.cs | 20 ++++ .../LINGYUN/Abp/Exporter/IImporterProvider.cs | 19 ++++ .../Localization/AbpExporterResource.cs | 8 ++ .../Exporter/Localization/Resources/en.json | 6 + .../Localization/Resources/zh-Hans.json | 6 + .../Abp/Exporter/NullExporterProvider.cs | 17 +++ .../Abp/Exporter/NullImporterProvider.cs | 18 +++ .../LINGYUN.Abp.Exporter.Core/README.md | 76 +++++++++++++ .../FodyWeavers.xml | 3 + .../LINGYUN.Abp.Exporter.HttpApi.csproj | 24 ++++ .../Abp/Exporter/AbpExporterHttpApiModule.cs | 12 ++ .../Abp/Exporter/ExporterController.cs | 22 ++++ .../Abp/Exporter/ImporterController.cs | 24 ++++ .../FodyWeavers.xml | 3 + ...GYUN.Abp.Exporter.MagicodesIE.Excel.csproj | 26 +++++ .../AbpExporterMagicodesIEExcelModule.cs | 30 +++++ .../AbpExporterMagicodesIEExcelOptions.cs | 31 ++++++ .../LINGYUN/Abp/Exporter/AbpImportHelper.cs | 23 ++++ .../MagicodesIEExcelExporterProvider.cs | 62 +++++++++++ .../MagicodesIEExcelImporterProvider.cs | 74 +++++++++++++ .../README.md | 41 +++++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ .../LINGYUN.Abp.Exporter.MiniExcel.csproj | 25 +++++ .../Exporter/AbpExporterMiniExcelModule.cs | 22 ++++ .../Exporter/AbpExporterMiniExcelOptions.cs | 25 +++++ .../Abp/Exporter/MiniExcelExporterProvider.cs | 41 +++++++ .../Abp/Exporter/MiniExcelImporterProvider.cs | 35 ++++++ .../LINGYUN.Abp.Exporter.MiniExcel/README.md | 46 ++++++++ 47 files changed, 1243 insertions(+) create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/FodyWeavers.xml create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/FodyWeavers.xsd create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN.Abp.Exporter.Application.Contracts.csproj create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/AbpExporterApplicationContractsModule.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/IExporterAppService.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/IImporterAppService.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/README.md create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/FodyWeavers.xml create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/FodyWeavers.xsd create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN.Abp.Exporter.Application.csproj create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/AbpExporterApplicationModule.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/ExporterAppService.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/ImporterAppService.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/FodyWeavers.xml create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/FodyWeavers.xsd create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN.Abp.Exporter.Core.csproj create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/AbpExporterCoreModule.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/ExporterErrorCodes.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/IExporterProvider.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/IImporterProvider.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/AbpExporterResource.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/Resources/en.json create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/Resources/zh-Hans.json create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/NullExporterProvider.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/NullImporterProvider.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/README.md create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/FodyWeavers.xml create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN.Abp.Exporter.HttpApi.csproj create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/AbpExporterHttpApiModule.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/ExporterController.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/ImporterController.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/FodyWeavers.xml create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN.Abp.Exporter.MagicodesIE.Excel.csproj create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpExporterMagicodesIEExcelModule.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpExporterMagicodesIEExcelOptions.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpImportHelper.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/MagicodesIEExcelExporterProvider.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/MagicodesIEExcelImporterProvider.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/README.md create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/FodyWeavers.xml create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/FodyWeavers.xsd create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN.Abp.Exporter.MiniExcel.csproj create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/AbpExporterMiniExcelModule.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/AbpExporterMiniExcelOptions.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelExporterProvider.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs create mode 100644 aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/README.md diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/FodyWeavers.xml b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/FodyWeavers.xsd b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN.Abp.Exporter.Application.Contracts.csproj b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN.Abp.Exporter.Application.Contracts.csproj new file mode 100644 index 000000000..bc998ef75 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN.Abp.Exporter.Application.Contracts.csproj @@ -0,0 +1,20 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0 + LINGYUN.Abp.Exporter.Application.Contracts + LINGYUN.Abp.Exporter.Application.Contracts + false + false + false + + + + + + + + diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/AbpExporterApplicationContractsModule.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/AbpExporterApplicationContractsModule.cs new file mode 100644 index 000000000..49523b1fb --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/AbpExporterApplicationContractsModule.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Application; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Exporter; + +[DependsOn(typeof(AbpDddApplicationContractsModule))] +public class AbpExporterApplicationContractsModule : AbpModule +{ +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/IExporterAppService.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/IExporterAppService.cs new file mode 100644 index 000000000..34e3177b6 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/IExporterAppService.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Volo.Abp.Content; + +namespace LINGYUN.Abp.Exporter; +/// +/// 数据导出服务接口 +/// +/// 导出的实体数据传输对象 +/// 实体数据过滤数据对象 +public interface IExporterAppService + where TEntityExportDto : class, new() +{ + /// + /// 导出数据(默认实现Excel) + /// + /// 数据过滤条件 + /// + Task ExportAsync(TEntityListGetInput input); +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/IImporterAppService.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/IImporterAppService.cs new file mode 100644 index 000000000..d2a6f30c3 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/LINGYUN/Abp/Exporter/IImporterAppService.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Exporter; +/// +/// 数据导入服务接口 +/// +/// +public interface IImporterAppService + where TEntityImportDto: class, new() +{ + /// + /// 导入数据(默认从Excel) + /// + /// 导入的数据文件流 + /// + Task ImportAsync(TEntityImportDto input); +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/README.md b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/README.md new file mode 100644 index 000000000..aac0f9666 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application.Contracts/README.md @@ -0,0 +1,103 @@ +# LINGYUN.Abp.Exporter.Application.Contracts + +数据导出/导入接口契约层,定义通用的数据导入/导入服务接口 + +## 配置使用 + + +> 配置模块依赖 +```csharp + +[DependsOn( + typeof(AbpExporterApplicationContractsModule) + )] +public class YouProjectModule : AbpModule +{ + +} +``` + +> 定义导出类型 +```csharp +public class DemoClassDto +{ + public string Name { get; set; } + public string Remarks { get; set; } + + public DemoClassDto() + { + } +} +``` + +> 定义导入类型 +```csharp +public class DemoClassImportInput +{ + [Required] + public IRemoteStreamContent Content { get; set; } + + public DemoClassImportInput() + { + } +} +``` + +> 定义数据过滤类型 +```csharp +public class DemoClassExportListInput +{ + public string Filter { get; set; } + + [Required] + public string FileName { get; set; } + + public DemoClassExportListInput() + { + } +} +``` + +> 导出数据 +```csharp + public class ExportDemoClassExportAppService : IExporterAppService + { + private readonly IExporterProvider _exporterProvider; + + public ExportDemoClassExportAppService(IExporterProvider exporterProvider) + { + _exporterProvider = exporterProvider; + } + + public async virtual Task ExportAsync(DemoClassExportListInput input) + { + var dtos = 通过仓储接口查询数据列表; + + var stream = await _exporterProvider.ExportAsync(dtos); + + return new RemoteStreamContent(stream, input.FileName); + } + } +``` + +> 导入数据 +```csharp + public class ExportDemoClassImportAppService : IImporterAppService + { + private readonly IImporterProvider _importerProvider; + + public ExportDemoClassImportAppService(IImporterProvider importerProvider) + { + _importerProvider = importerProvider; + } + + public async virtual Task ImportAsync(DemoClassImportInput input) + { + var stream = input.Content.GetStream(); + + var demos = await _importerProvider.ImportAsync(stream); + + // 其他操作 + } + } +``` diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/FodyWeavers.xml b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/FodyWeavers.xsd b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN.Abp.Exporter.Application.csproj b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN.Abp.Exporter.Application.csproj new file mode 100644 index 000000000..33ae7de47 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN.Abp.Exporter.Application.csproj @@ -0,0 +1,25 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0 + LINGYUN.Abp.Exporter.Application + LINGYUN.Abp.Exporter.Application + false + false + false + + + + + + + + + + + + + diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/AbpExporterApplicationModule.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/AbpExporterApplicationModule.cs new file mode 100644 index 000000000..022b0a7d5 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/AbpExporterApplicationModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Application; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Exporter; + +[DependsOn( + typeof(AbpDddApplicationModule), + typeof(AbpExporterCoreModule), + typeof(AbpExporterApplicationContractsModule))] +public class AbpExporterApplicationModule : AbpModule +{ +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/ExporterAppService.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/ExporterAppService.cs new file mode 100644 index 000000000..2ccc95eb8 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/ExporterAppService.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.Content; + +namespace LINGYUN.Abp.Exporter; + +public abstract class ExporterAppService : ApplicationService, IExporterAppService + where TEntityExportDto : class, new() +{ + private readonly IExporterProvider _exporterProvider; + + protected ExporterAppService(IExporterProvider exporterProvider) + { + _exporterProvider = exporterProvider; + } + + public async virtual Task ExportAsync(TEntityListGetInput input) + { + var fileName = GetExportFileName(input); + + var entities = await GetListAsync(input); + var entitieDtoList = MapEntitiesToDto(entities); + + var stream = await _exporterProvider.ExportAsync(entitieDtoList); + + return new RemoteStreamContent(stream, fileName); + } + /// + /// 实现方法用以返回导出文件名 + /// + /// + /// + protected abstract string GetExportFileName(TEntityListGetInput input); + /// + /// 实现方法用以查询需要导出的实体列表 + /// + /// + /// + protected abstract Task> GetListAsync(TEntityListGetInput input); + /// + /// 实现方法用以实体数据传输对象映射 + /// + /// + /// + protected virtual List MapEntitiesToDto(List entities) + { + return ObjectMapper.Map, List>(entities); + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/ImporterAppService.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/ImporterAppService.cs new file mode 100644 index 000000000..0e6735029 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Application/LINGYUN/Abp/Exporter/ImporterAppService.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; + +namespace LINGYUN.Abp.Exporter; + +public abstract class ImporterAppService : ApplicationService, IImporterAppService + where TEntityImportDto : class, new() +{ + private readonly IImporterProvider _importerProvider; + protected ImporterAppService(IImporterProvider importerProvider) + { + _importerProvider = importerProvider; + } + + public async virtual Task ImportAsync(TEntityImportDto input) + { + var stream = await GetImportStream(input); + var entitieDtoList = await _importerProvider.ImportAsync(stream); + + var entities = MapDtoToEntities([.. entitieDtoList]); + + await SaveManyEntities(entities); + } + /// + /// 实现方法用以从导入数据中提取文件流 + /// + /// + /// + protected abstract Task GetImportStream(TEntityImportDto input); + /// + /// 实现方法用以保存实体列表到持久化设施 + /// + /// + /// + protected abstract Task SaveManyEntities(ICollection entities); + /// + /// 实现方法用以实体数据传输对象映射 + /// + /// + /// + protected virtual List MapDtoToEntities(List entitieDtoList) + { + return ObjectMapper.Map, List>(entitieDtoList); + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/FodyWeavers.xml b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/FodyWeavers.xml new file mode 100644 index 000000000..00e1d9a1c --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/FodyWeavers.xsd b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN.Abp.Exporter.Core.csproj b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN.Abp.Exporter.Core.csproj new file mode 100644 index 000000000..aa94a35e8 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN.Abp.Exporter.Core.csproj @@ -0,0 +1,30 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0 + LINGYUN.Abp.Exporter.Core + LINGYUN.Abp.Exporter.Core + false + false + false + enable + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/AbpExporterCoreModule.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/AbpExporterCoreModule.cs new file mode 100644 index 000000000..5ba31e424 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/AbpExporterCoreModule.cs @@ -0,0 +1,31 @@ +using LINGYUN.Abp.Exporter.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Localization.ExceptionHandling; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace LINGYUN.Abp.Exporter; + +[DependsOn(typeof(AbpLocalizationModule))] +public class AbpExporterCoreModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/LINGYUN/Abp/Exporter/Localization/Resources"); + }); + + Configure(options => + { + options.MapCodeNamespace(ExporterErrorCodes.Namespace, typeof(AbpExporterResource)); + }); + } +} \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/ExporterErrorCodes.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/ExporterErrorCodes.cs new file mode 100644 index 000000000..9ad0cc137 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/ExporterErrorCodes.cs @@ -0,0 +1,9 @@ +namespace LINGYUN.Abp.Exporter; +public static class ExporterErrorCodes +{ + public const string Namespace = "AbpExporter"; + /// + /// 导入数据过程中出现一些错误,请检查数据有效性! + /// + public const string ImportDataError = Namespace + ":010001"; +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/IExporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/IExporterProvider.cs new file mode 100644 index 000000000..0f31c7b70 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/IExporterProvider.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Exporter; +/// +/// 数据导出提供者 +/// +public interface IExporterProvider +{ + /// + /// 数据导出 + /// + /// 导出数据 + /// + /// + Task ExportAsync(ICollection data, CancellationToken cancellationToken = default) + where T : class, new(); +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/IImporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/IImporterProvider.cs new file mode 100644 index 000000000..f1b0673dd --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/IImporterProvider.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace LINGYUN.Abp.Exporter; +/// +/// 数据导入提供者 +/// +public interface IImporterProvider +{ + /// + /// 数据导入 + /// + /// + /// + /// + Task> ImportAsync(Stream stream) + where T : class, new(); +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/AbpExporterResource.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/AbpExporterResource.cs new file mode 100644 index 000000000..e80ccb5f3 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/AbpExporterResource.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.Exporter.Localization; + +[LocalizationResourceName("AbpExporter")] +public class AbpExporterResource +{ +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/Resources/en.json b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/Resources/en.json new file mode 100644 index 000000000..ff6718836 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/Resources/en.json @@ -0,0 +1,6 @@ +{ + "culture": "en", + "texts": { + "AbpExporter:010001": "There were some errors during the data import process. Please check the validity of the data!" + } +} \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/Resources/zh-Hans.json b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/Resources/zh-Hans.json new file mode 100644 index 000000000..e867e5cdb --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/Localization/Resources/zh-Hans.json @@ -0,0 +1,6 @@ +{ + "culture": "zh-Hans", + "texts": { + "AbpExporter:010001": "导入数据过程中出现一些错误,请检查数据有效性!" + } +} \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/NullExporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/NullExporterProvider.cs new file mode 100644 index 000000000..89457daf4 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/NullExporterProvider.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Exporter; + +[Dependency(TryRegister = true)] +public class NullExporterProvider : IExporterProvider, ISingletonDependency +{ + private readonly static Stream _nullStreamCache = Stream.Null; + public Task ExportAsync(ICollection data, CancellationToken cancellationToken = default) where T : class, new() + { + return Task.FromResult(_nullStreamCache); + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/NullImporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/NullImporterProvider.cs new file mode 100644 index 000000000..032428a4a --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/LINGYUN/Abp/Exporter/NullImporterProvider.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Exporter; + +[Dependency(TryRegister = true)] +public class NullImporterProvider : IImporterProvider, ISingletonDependency +{ + public Task> ImportAsync(Stream stream) where T : class, new() + { + IReadOnlyCollection empty = Array.Empty(); + + return Task.FromResult(empty); + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/README.md b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/README.md new file mode 100644 index 000000000..4993d9489 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.Core/README.md @@ -0,0 +1,76 @@ +# LINGYUN.Abp.Exporter.Core + +数据导出/导入核心层 + +## 配置使用 + + +```csharp + + [DependsOn( + typeof(AbpExporterCoreModule) + )] + public class YouProjectModule : AbpModule + { + + } +``` + +> 导出数据 +```csharp + public class ExportDemoClass + { + private readonly IExporterProvider _exporterProvider; + + public ExportDemoClass(IExporterProvider exporterProvider) + { + _exporterProvider = exporterProvider; + } + + public async virtual Task ExportAsync() + { + var dataItems = new object[] + { + new + { + Name = "name1", + Remakrs = "remarks1" + } + }; + + var stream = await _exporterProvider.ExportAsync(dataItems); + + return new RemoteStreamContent(stream, "demo.xlsx"); + } + } +``` + +> 导入数据 +```csharp + public class ImportDemoClass + { + private readonly IImporterProvider _importerProvider; + + public ImportDemoClass(IImporterProvider importerProvider) + { + _importerProvider = importerProvider; + } + + public async virtual Task ImportAsync(Stream stream) + { + var demos = await _importerProvider.ImportAsync(stream); + + // 其他操作 + } + } + + public class DemoClass + { + public string Name { get; set; } + public string Remarks { get; set; } + + public DemoClass() + { + } + } +``` diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/FodyWeavers.xml b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN.Abp.Exporter.HttpApi.csproj b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN.Abp.Exporter.HttpApi.csproj new file mode 100644 index 000000000..93bd013ba --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN.Abp.Exporter.HttpApi.csproj @@ -0,0 +1,24 @@ + + + + + + + net8.0 + LINGYUN.Abp.Exporter.HttpApi + LINGYUN.Abp.Exporter.HttpApi + false + false + false + + + + + + + + + + + + diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/AbpExporterHttpApiModule.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/AbpExporterHttpApiModule.cs new file mode 100644 index 000000000..01313663a --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/AbpExporterHttpApiModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Application; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Exporter; + +[DependsOn( + typeof(AbpDddApplicationModule), + typeof(AbpExporterApplicationContractsModule))] +public class AbpExporterHttpApiModule : AbpModule +{ + +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/ExporterController.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/ExporterController.cs new file mode 100644 index 000000000..189363efa --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/ExporterController.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Content; + +namespace LINGYUN.Abp.Exporter; +public abstract class ExporterController : AbpControllerBase, IExporterAppService + where TEntityExportDto : class, new() +{ + private readonly IExporterAppService _exportService; + protected ExporterController(IExporterAppService exportService) + { + _exportService = exportService; + } + + [HttpGet] + [Route("export")] + public virtual Task ExportAsync(TEntityListGetInput input) + { + return _exportService.ExportAsync(input); + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/ImporterController.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/ImporterController.cs new file mode 100644 index 000000000..42212ba56 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.HttpApi/LINGYUN/Abp/Exporter/ImporterController.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Mvc; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Content; + +namespace LINGYUN.Abp.Exporter; + +public abstract class ImporterController : AbpControllerBase, IImporterAppService + where TEntityImportDto : class, new() +{ + private readonly IImporterAppService _importService; + + protected ImporterController(IImporterAppService importService) + { + _importService = importService; + } + + [HttpPost] + [Route("import")] + public virtual Task ImportAsync(IRemoteStreamContent input) + { + return _importService.ImportAsync(input); + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/FodyWeavers.xml b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN.Abp.Exporter.MagicodesIE.Excel.csproj b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN.Abp.Exporter.MagicodesIE.Excel.csproj new file mode 100644 index 000000000..092ee9876 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN.Abp.Exporter.MagicodesIE.Excel.csproj @@ -0,0 +1,26 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0 + LINGYUN.Abp.Exporter.MagicodesIE.Excel + LINGYUN.Abp.Exporter.MagicodesIE.Excel + false + false + false + enable + + + + + + + + + + + + + diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpExporterMagicodesIEExcelModule.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpExporterMagicodesIEExcelModule.cs new file mode 100644 index 000000000..27c929fa8 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpExporterMagicodesIEExcelModule.cs @@ -0,0 +1,30 @@ +using Magicodes.ExporterAndImporter.Core; +using Magicodes.ExporterAndImporter.Excel; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Exporter.MiniExcel; + +[DependsOn(typeof(AbpExporterCoreModule))] +public class AbpExporterMagicodesIEExcelModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddScoped(); + + context.Services.AddScoped(); + + context.Services.AddScoped(); + + context.Services.Replace( + ServiceDescriptor.Transient( + typeof(IExporterProvider), + typeof(MagicodesIEExcelExporterProvider))); + + context.Services.Replace( + ServiceDescriptor.Transient( + typeof(IImporterProvider), + typeof(MagicodesIEExcelImporterProvider))); + } +} \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpExporterMagicodesIEExcelOptions.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpExporterMagicodesIEExcelOptions.cs new file mode 100644 index 000000000..19857d592 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpExporterMagicodesIEExcelOptions.cs @@ -0,0 +1,31 @@ +using Magicodes.ExporterAndImporter.Excel; +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Exporter; +public class AbpExporterMagicodesIEExcelOptions +{ + /// + /// 数据导出设置 + /// + public IDictionary> ExportSettingMapping { get; } + /// + /// 数据导入设置 + /// + public IDictionary> ImportSettingMapping { get; } + public AbpExporterMagicodesIEExcelOptions() + { + ExportSettingMapping = new Dictionary>(); + ImportSettingMapping = new Dictionary>(); + } + + public void MapExportSetting(Type dataType, Action exportSettingsSetup) + { + ExportSettingMapping[dataType] = exportSettingsSetup; + } + + public void MapImportSetting(Type dataType, Action importSettingsSetup) + { + ImportSettingMapping[dataType] = importSettingsSetup; + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpImportHelper.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpImportHelper.cs new file mode 100644 index 000000000..a494896bd --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/AbpImportHelper.cs @@ -0,0 +1,23 @@ +using Magicodes.ExporterAndImporter.Excel; +using Magicodes.ExporterAndImporter.Excel.Utility; +using System; +using System.IO; + +namespace LINGYUN.Abp.Exporter; +public class AbpImportHelper : ImportHelper where T : class, new() +{ + public AbpImportHelper(string? filePath = null, string? labelingFilePath = null) + : base(filePath, labelingFilePath) + { + } + + public AbpImportHelper(Stream stream, Stream? labelingFileStream) + : base(stream, labelingFileStream) + { + } + + internal void ConfigureExcelImportSettings(Action? excelImportSettingsConfig) + { + excelImportSettingsConfig?.Invoke(ExcelImporterSettings); + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/MagicodesIEExcelExporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/MagicodesIEExcelExporterProvider.cs new file mode 100644 index 000000000..6a5e96d48 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/MagicodesIEExcelExporterProvider.cs @@ -0,0 +1,62 @@ +using Magicodes.ExporterAndImporter.Excel; +using Magicodes.ExporterAndImporter.Excel.Utility; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Exporter; +public class MagicodesIEExcelExporterProvider : IExporterProvider, ITransientDependency +{ + private readonly AbpExporterMagicodesIEExcelOptions _options; + private readonly IExcelExporter _excelExporter; + + public MagicodesIEExcelExporterProvider(IOptions options) + { + _options = options.Value; + } + + public async virtual Task ExportAsync(ICollection data, CancellationToken cancellationToken = default) + where T : class, new() + { + var fileBytes = new List(); + + var exportHelper = new ExportHelper(); + + // 由于Microsoft.IE.Excel官方此接口未暴露用户配置,做一次转换 + if (_options.ExportSettingMapping.TryGetValue(typeof(T), out var exportSetting)) + { + exportSetting?.Invoke(exportHelper.ExcelExporterSettings); + } + + if (exportHelper.ExcelExporterSettings.MaxRowNumberOnASheet > 0 && data.Count > exportHelper.ExcelExporterSettings.MaxRowNumberOnASheet) + { + using (exportHelper.CurrentExcelPackage) + { + var num = data.Count / exportHelper.ExcelExporterSettings.MaxRowNumberOnASheet + ((data.Count % exportHelper.ExcelExporterSettings.MaxRowNumberOnASheet > 0) ? 1 : 0); + for (var i = 0; i < num; i++) + { + var dataItems2 = data.Skip(i * exportHelper.ExcelExporterSettings.MaxRowNumberOnASheet).Take(exportHelper.ExcelExporterSettings.MaxRowNumberOnASheet).ToList(); + exportHelper.AddExcelWorksheet(); + exportHelper.Export(dataItems2); + } + + fileBytes.AddRange(await exportHelper.CurrentExcelPackage.GetAsByteArrayAsync()); + } + } + else + { + using var excelPackage2 = exportHelper.Export(data); + fileBytes.AddRange(await excelPackage2.GetAsByteArrayAsync()); + } + + var memoryStream = new MemoryStream([.. fileBytes]); + + memoryStream.Seek(0, SeekOrigin.Begin); + + return memoryStream; + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/MagicodesIEExcelImporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/MagicodesIEExcelImporterProvider.cs new file mode 100644 index 000000000..ed4e8a31b --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/LINGYUN/Abp/Exporter/MagicodesIEExcelImporterProvider.cs @@ -0,0 +1,74 @@ +using Magicodes.ExporterAndImporter.Core.Models; +using Magicodes.ExporterAndImporter.Excel; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Json; + +namespace LINGYUN.Abp.Exporter; + +public class MagicodesIEExcelImporterProvider : IImporterProvider, ITransientDependency +{ + public ILogger Logger { protected get; set; } + + private readonly AbpExporterMagicodesIEExcelOptions _options; + private readonly IJsonSerializer _jsonSerializer; + private readonly IExcelImporter _excelImporter; + + public MagicodesIEExcelImporterProvider( + IJsonSerializer jsonSerializer, + IExcelImporter excelImporter, + IOptions options) + { + _jsonSerializer = jsonSerializer; + _excelImporter = excelImporter; + _options = options.Value; + + Logger = NullLogger.Instance; + } + + public async virtual Task> ImportAsync(Stream stream) where T : class, new() + { + using var importHelper = new AbpImportHelper(stream, null); + + // 由于Microsoft.IE.Excel官方此接口未暴露用户配置,做一次转换 + if (_options.ImportSettingMapping.TryGetValue(typeof(T), out var importSetting)) + { + importHelper.ConfigureExcelImportSettings(importSetting); + } + + var importResult = await importHelper.Import(null, null); + + ThrowImportException(importResult); + + return importResult.Data.ToImmutableList(); + } + + protected virtual void ThrowImportException(ImportResult importResult) where T : class, new() + { + if (importResult.HasError) + { + if (importResult.RowErrors.Count > 0) + { + var errorJson = _jsonSerializer.Serialize(importResult.RowErrors); + Logger.LogWarning("Row validation error occurred during data import process, details: {errorJson}", errorJson); + } + + if (importResult.TemplateErrors.Count > 0) + { + var errorJson = _jsonSerializer.Serialize(importResult.TemplateErrors); + Logger.LogWarning("Template validation error occurred during data import process, details: {errorJson}", errorJson); + } + + throw new BusinessException( + code: ExporterErrorCodes.ImportDataError, + innerException: importResult.Exception); + } + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/README.md b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/README.md new file mode 100644 index 000000000..ed9fc65f9 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MagicodesIE.Excel/README.md @@ -0,0 +1,41 @@ +# LINGYUN.Abp.Exporter.MagicodesIE.Excel + +数据导出接口的 [Magicodes.IE.Excel](https://github.com/dotnetcore/Magicodes.IE) 实现 + +Import and export general library, support Dto import and export, template export, fancy export and dynamic export, support Excel, Csv, Word, Pdf and Html. + +详情请参考 [Magicodes.IE.Excel 文档](https://github.com/dotnetcore/Magicodes.IE/blob/master/docs/2.%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B%E4%B9%8B%E5%AF%BC%E5%87%BAExcel.md) + +## 配置使用 + + +```csharp + + [DependsOn( + typeof(AbpExporterMagicodesIEExcelModule) + )] + public class YouProjectModule : AbpModule + { + Configure(options => + { + // 配置类型数据导出 + options.MapExportSetting(typeof(DemoClass), config => + { + // 表头位置从第二行开始 + config.HeaderRowIndex = 2; + // 其他配置 + }); + }); + } + + public class DemoClass + { + public string Name { get; set; } + public string Remarks { get; set; } + + public DemoClass() + { + } + } +``` + diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/FodyWeavers.xml b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/FodyWeavers.xsd b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/FodyWeavers.xsd new file mode 100644 index 000000000..3f3946e28 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN.Abp.Exporter.MiniExcel.csproj b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN.Abp.Exporter.MiniExcel.csproj new file mode 100644 index 000000000..2efc4c367 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN.Abp.Exporter.MiniExcel.csproj @@ -0,0 +1,25 @@ + + + + + + + netstandard2.0;netstandard2.1;net8.0 + LINGYUN.Abp.Exporter.MiniExcel + LINGYUN.Abp.Exporter.MiniExcel + false + false + false + enable + + + + + + + + + + + + diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/AbpExporterMiniExcelModule.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/AbpExporterMiniExcelModule.cs new file mode 100644 index 000000000..000e26636 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/AbpExporterMiniExcelModule.cs @@ -0,0 +1,22 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Exporter.MiniExcel; + +[DependsOn(typeof(AbpExporterCoreModule))] +public class AbpExporterMiniExcelModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.Replace( + ServiceDescriptor.Transient( + typeof(IExporterProvider), + typeof(MiniExcelExporterProvider))); + + context.Services.Replace( + ServiceDescriptor.Transient( + typeof(IImporterProvider), + typeof(MiniExcelImporterProvider))); + } +} \ No newline at end of file diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/AbpExporterMiniExcelOptions.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/AbpExporterMiniExcelOptions.cs new file mode 100644 index 000000000..b51cddc8e --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/AbpExporterMiniExcelOptions.cs @@ -0,0 +1,25 @@ +using MiniExcelLibs.OpenXml; +using System; +using System.Collections.Generic; + +namespace LINGYUN.Abp.Exporter; +public class AbpExporterMiniExcelOptions +{ + public IDictionary> ExportSettingMapping { get; } + public IDictionary> ImportSettingMapping { get; } + public AbpExporterMiniExcelOptions() + { + ExportSettingMapping = new Dictionary>(); + ImportSettingMapping = new Dictionary>(); + } + + public void MapExportSetting(Type dataType, Action settingMapping) + { + ExportSettingMapping[dataType] = settingMapping; + } + + public void MapImportSetting(Type dataType, Action settingMapping) + { + ImportSettingMapping[dataType] = settingMapping; + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelExporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelExporterProvider.cs new file mode 100644 index 000000000..258f333a1 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelExporterProvider.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.Options; +using MiniExcelLibs; +using MiniExcelLibs.OpenXml; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Exporter; +public class MiniExcelExporterProvider : IExporterProvider, ITransientDependency +{ + private readonly AbpExporterMiniExcelOptions _options; + + public MiniExcelExporterProvider(IOptions options) + { + _options = options.Value; + } + + public async virtual Task ExportAsync(ICollection data, CancellationToken cancellationToken = default) + where T : class, new() + { + var memoryStream = new MemoryStream(); + var xmlConfig = new OpenXmlConfiguration(); + + if (_options.ExportSettingMapping.TryGetValue(typeof(T), out var exportSetting)) + { + exportSetting?.Invoke(xmlConfig); + } + + await memoryStream.SaveAsAsync( + value: data, + excelType: ExcelType.XLSX, + configuration: xmlConfig, + cancellationToken: cancellationToken); + + memoryStream.Seek(0, SeekOrigin.Begin); + + return memoryStream; + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs new file mode 100644 index 000000000..3a0d7b3d4 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/LINGYUN/Abp/Exporter/MiniExcelImporterProvider.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.Options; +using MiniExcelLibs; +using MiniExcelLibs.OpenXml; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace LINGYUN.Abp.Exporter; +public class MiniExcelImporterProvider : IImporterProvider, ITransientDependency +{ + private readonly AbpExporterMiniExcelOptions _options; + + public MiniExcelImporterProvider(IOptions options) + { + _options = options.Value; + } + + public async virtual Task> ImportAsync(Stream stream) where T : class, new() + { + var xmlConfig = new OpenXmlConfiguration(); + + if (_options.ExportSettingMapping.TryGetValue(typeof(T), out var exportSetting)) + { + exportSetting?.Invoke(xmlConfig); + } + + var dataList = await stream.QueryAsync( + excelType: ExcelType.XLSX, + configuration: xmlConfig); + + return dataList.ToImmutableList(); + } +} diff --git a/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/README.md b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/README.md new file mode 100644 index 000000000..da5ceb973 --- /dev/null +++ b/aspnet-core/framework/exporter/LINGYUN.Abp.Exporter.MiniExcel/README.md @@ -0,0 +1,46 @@ +# LINGYUN.Abp.Exporter.MiniExcel + +数据导出接口的 [MiniExcel](https://github.com/mini-software/MiniExcel) 实现 + +MiniExcel简单、高效避免OOM的.NET处理Excel查、写、填充数据工具。 + +目前主流框架大多需要将数据全载入到内存方便操作,但这会导致内存消耗问题,MiniExcel 尝试以 Stream 角度写底层算法逻辑,能让原本1000多MB占用降低到几MB,避免内存不够情况。 + +详情请参考 [MiniExcel 文档](https://github.com/mini-software/MiniExcel/blob/master/README.md) + +## 配置使用 + + +```csharp + + [DependsOn( + typeof(AbpExporterMiniExcelModule) + )] + public class YouProjectModule : AbpModule + { + Configure(options => + { + // 配置类型数据导出 + options.MapExportSetting(typeof(DemoClass), config => + { + config.DynamicColumns = new[] + { + // 忽略Name字段 + new DynamicExcelColumn(nameof(DemoClass.Name)){ Ignore = true }, + // 其他配置 + }; + }); + }); + } + + public class DemoClass + { + public string Name { get; set; } + public string Remarks { get; set; } + + public DemoClass() + { + } + } +``` +