Magicodes.IE之導入導出篩選器


總體設計

總體設計
 

Magicodes.IE是一個導入導出通用庫,支持Dto導入導出以及動態導出,支持Excel、Word、Pdf、Csv和Html。在本篇教程,筆者將講述如何使用Magicodes.IE的導入導出篩選器。在開始之前,我們需要先了解Magicodes.IE目前支持的篩選器:

接口 說明
IImportResultFilter 導入結果篩選器,可以修改導入結果包括驗證錯誤信息(比如動態修改錯誤標注)
IImportHeaderFilter 導入列頭篩選器,可以修改列名、值映射集合等等
IExporterHeaderFilter 導出列頭篩選器,可以修改列頭、索引、值映射等等

導入結果篩選器(IImportResultFilter)的使用

導入結果篩選器可以修改導入結果包括驗證錯誤信息(比如動態修改錯誤標注),非常適合對導入數據和錯誤驗證內容進行二次動態加工,比如加入自定義校驗邏輯、驗證消息多語言翻譯等等。接下來我們開始實戰:

准備導入文件

如下圖所示,我們准備了如下Excel導入文件:

導入文件

下載地址

准備Dto

Excel准備好了,我們需要准備一個Dto:

[ExcelImporter(ImportResultFilter = typeof(ImportResultFilterTest), IsLabelingError = true)]
public class ImportResultFilterDataDto1
{
    /// <summary>
    ///     產品名稱
    /// </summary>
    [ImporterHeader(Name = "產品名稱")]
    public string Name { get; set; }

    /// <summary>
    ///     產品代碼
    ///     長度驗證
    ///     重復驗證
    /// </summary>
    [ImporterHeader(Name = "產品代碼", Description = "最大長度為20", AutoTrim = false, IsAllowRepeat = false)]
    public string Code { get; set; }
}

如上述代碼所示,我們創建了名為“ImportResultFilterDataDto1”的Dto,使用ExcelImporter特性中的ImportResultFilter屬性指定了導入結果篩選器的類型。

創建類並實現接口IImportResultFilter

接下來我們就創建一個類並實現IImportResultFilter接口:

public class ImportResultFilterTest : IImportResultFilter
{
    /// <summary>
    /// 本示例修改數據錯誤驗證結果,可用於多語言等場景
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="importResult"></param>
    /// <returns></returns>
    public ImportResult<T> Filter<T>(ImportResult<T> importResult) where T : class, new()
    {
        var errorRows = new List<int>()
        {
            5,6
        };
        var items = importResult.RowErrors.Where(p => errorRows.Contains(p.RowIndex)).ToList();

        for (int i = 0; i < items.Count; i++)
        {
            for (int j = 0; j < items[i].FieldErrors.Keys.Count; j++)
            {
                var key = items[i].FieldErrors.Keys.ElementAt(j);
                var value = items[i].FieldErrors[key];
                items[i].FieldErrors[key] = value?.Replace("存在數據重復,請檢查!所在行:", "Duplicate data exists, please check! Where:");
            }
        }
        return importResult;
    }
}

如上述代碼所示,我們將重復錯誤的驗證提示修改為了“Duplicate data exists, please check! Where”。接下來,我們需要編寫導入代碼:

編寫導入代碼

 public async Task ImportResultFilter_Test()
    {
        var filePath = Path.Combine(Directory.GetCurrentDirectory(), "TestFiles", "Errors", "數據錯誤.xlsx");
        var labelingFilePath = Path.Combine(Directory.GetCurrentDirectory(), $"{nameof(ImportResultFilter_Test)}.xlsx");
        var result = await Importer.Import<ImportResultFilterDataDto1>(filePath, labelingFilePath);
    }

打開上述代碼所示的標注文件路徑,就可以看到驗證提示被我們改成了英文:

驗證提示
 

導入列頭篩選器(IImportHeaderFilter)的使用

導入列頭篩選器可以修改列名、驗證屬性、值映射集合等等,非常適合動態修改列名、驗證邏輯、值映射等等。和前面的一樣,我們先得准備一個導入文件。

准備導入文件

導入文件

下載地址

准備Dto

/// <summary>
/// 導入學生數據Dto
/// IsLabelingError:是否標注數據錯誤
/// </summary>
[ExcelImporter(IsLabelingError = true, ImportHeaderFilter = typeof(ImportHeaderFilterTest))]
public class ImportHeaderFilterDataDto1
{
    /// <summary>
    ///     姓名
    /// </summary>
    [ImporterHeader(Name = "姓名", Author = "雪雁")]
    [Required(ErrorMessage = "學生姓名不能為空")]
    [MaxLength(50, ErrorMessage = "名稱字數超出最大限制,請修改!")]
    public string Name { get; set; }

    /// <summary>
    ///     性別
    /// </summary>
    [ImporterHeader(Name = "性別")]
    [Required(ErrorMessage = "性別不能為空")]
    public Genders Gender { get; set; }

}

如上述代碼所示,我們通過ImportHeaderFilter屬性指定了列頭篩選器類型。接下來,我們需要完成相關實現:

創建類並實現接口IImportHeaderFilter

/// <summary>
/// 導入列頭篩選器測試
/// 1)測試修改列頭
/// 2)測試修改值映射
/// </summary>
public class ImportHeaderFilterTest : IImportHeaderFilter
{
    public List<ImporterHeaderInfo> Filter(List<ImporterHeaderInfo> importerHeaderInfos)
    {
        foreach (var item in importerHeaderInfos)
        {
            if (item.PropertyName == "Name")
            {
                item.Header.Name = "Student";
            }
            else if (item.PropertyName == "Gender")
            {
                item.MappingValues = new Dictionary<string, dynamic>()
                {
                    {"",0 },
                    {"",1 }
                };
            }
        }
        return importerHeaderInfos;
    }
}

通過上述代碼,我們編寫了一些測試:

  1. 實現了IImportHeaderFilter
  2. 將屬性名稱為“Name”的列的列頭修改為“Student”
  3. 將屬性名稱為“Gender”的列的列映射改為男女映射

接下來我們繼續編寫導入邏輯:

  public async Task ImportHeaderFilter_Test()
    {
        var filePath = Path.Combine(Directory.GetCurrentDirectory(), "TestFiles", "Import", "導入列頭篩選器測試.xlsx");
        var import = await Importer.Import<ImportHeaderFilterDataDto1>(filePath);
    }

如下圖所示,我們成功的將Excel列名為“Student”的列導入到了Dto的Name屬性,同時將男女轉換為了枚舉:

驗證
 

導出列頭篩選器(IExporterHeaderFilter)的使用

導出列頭篩選器可以修改列頭、索引、值映射,非常適合動態修改導出邏輯,比如列頭的中英轉換,值映射動態邏輯等等。接下來我們一起來實戰:

准備Dto並編寫導出代碼

[Exporter(Name = "測試", TableStyle = "Light10", ExporterHeaderFilter = typeof(TestExporterHeaderFilter1))]
public class ExporterHeaderFilterTestData1
{
    [ExporterHeader(DisplayName = "加粗文本", IsBold = true)]
    public string Text { get; set; }

    [ExporterHeader(DisplayName = "普通文本")] public string Text2 { get; set; }

    [ExporterHeader(DisplayName = "忽略", IsIgnore = true)]
    public string Text3 { get; set; }

    [ExporterHeader(DisplayName = "數值", Format = "#,##0")]
    public decimal Number { get; set; }

    [ExporterHeader(DisplayName = "名稱", IsAutoFit = true)]
    public string Name { get; set; }
}

如上述Dto代碼所示,我們通過導出特性Exporter的ExporterHeaderFilter屬性指定了導出列頭篩選器。

實現篩選器IExporterHeaderFilter

public class TestExporterHeaderFilter1 : IExporterHeaderFilter
{
    /// <summary>
    /// 表頭篩選器(修改名稱)
    /// </summary>
    /// <param name="exporterHeaderInfo"></param>
    /// <returns></returns>
    public ExporterHeaderInfo Filter(ExporterHeaderInfo exporterHeaderInfo)
    {
        if (exporterHeaderInfo.DisplayName.Equals("名稱"))
        {
            exporterHeaderInfo.DisplayName = "name";
        }
        return exporterHeaderInfo;
    }
}

如上述代碼所示,我們實現了導出篩選器,並將顯示名為“名稱”的列修改為了“name”。

編寫導出邏輯

//導出
IExporter exporter = new ExcelExporter();
//使用GenFu生成測試數據
var data1 = GenFu.GenFu.ListOf<ExporterHeaderFilterTestData1>();
var result = await exporter.Export(filePath, data1);

使用上述代碼導出后,我們來驗證導出結果:

導出結果

是不是So easy呢?當然我們還可以做一些其他的事情,比如修改忽略列:

public class TestExporterHeaderFilter2 : IExporterHeaderFilter
{
    /// <summary>
    /// 表頭篩選器(修改忽略列)
    /// </summary>
    /// <param name="exporterHeaderInfo"></param>
    /// <returns></returns>
    public ExporterHeaderInfo Filter(ExporterHeaderInfo exporterHeaderInfo)
    {
        if (exporterHeaderInfo.ExporterHeaderAttribute.IsIgnore)
        {
            exporterHeaderInfo.ExporterHeaderAttribute.IsIgnore = false;
        }
        return exporterHeaderInfo;
    }
}

如何使用容器注入篩選器

篩選器主要是為了滿足大家能夠在導入導出時支持動態處理,比如值映射等等。但是通過特性指定篩選器的話,那么如何支持依賴注入呢?不要慌,針對這個場景,我們也有考慮。

在ASP.NET Core的啟動類(StartUp)注冊容器

參考代碼如下:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    AppDependencyResolver.Init(app.ApplicationServices);
    //添加注入關系
    services.AddSingleton<IImportResultFilter, ImportResultFilterTest>();
    services.AddSingleton<IImportHeaderFilter, ImportHeaderFilterTest>();
    services.AddSingleton<IExporterHeaderFilter, TestExporterHeaderFilter1>();    
}

然后就盡情使用吧。值得注意的是:

  1. 注入的篩選器類型的優先級高於特性指定的篩選器類型,也就是當兩者並存時,優先會使用注入的篩選器
  2. 注入的篩選器是全局的,當注入多種類型的篩選器時,均會執行,接下來我們還會支持更多細節控制
  3. 如果某個邏輯需要禁用所有篩選器,請參考下面部分
  4. 此功能需要2.4.0-beta2或以上版本才支持

使用IsDisableAllFilter屬性禁用所有的篩選器

如果某段導入導出需要禁用所有的篩選器,我們該如何處理?僅需將IsDisableAllFilter設置為true即可。導入導出特性均已支持。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM