1.本文主要內(nèi)容為給Blazor工程構(gòu)建通用導(dǎo)入導(dǎo)出服務(wù)類
基礎(chǔ)工程構(gòu)建取自 [BootstrapBlazor實戰(zhàn) 10分鐘編寫數(shù)據(jù)庫維護(hù)] 項目,使用到的orm為freesql,導(dǎo)入導(dǎo)出庫為Magicodes.IE,還有封裝了Table組件的內(nèi)存數(shù)據(jù)服務(wù)LazyHeroDataService的Densen.FreeSql.Extensions.BootstrapBlazor庫.
主要實現(xiàn)功能(Table組件):
[編輯][添加][刪除]數(shù)據(jù)
[導(dǎo)出]現(xiàn)在表格數(shù)據(jù)
[清空]數(shù)據(jù)
[選擇文件]上傳并導(dǎo)入
[清空]數(shù)據(jù)后再選擇[導(dǎo)入]
[自由編輯]類似Excel模式編輯表格
最終運(yùn)行效果
2.使用 nuget.org 進(jìn)行必須的組件安裝
dotnet add b03sqlite package Magicodes.IE.Core
dotnet add b03sqlite package Magicodes.IE.Excel
dotnet add b03sqlite package Magicodes.IE.Html
dotnet add b03sqlite package Magicodes.IE.Pdf
dotnet add b03sqlite package Magicodes.IE.Word
dotnet add b03sqlite package Densen.FreeSql.Extensions.BootstrapBlazor
Densen.FreeSql.Extensions.BootstrapBlazor 庫封裝了Table組件的內(nèi)存數(shù)據(jù)服務(wù)LazyHeroDataService,因篇幅關(guān)系不展開介紹,需要了解的朋友請自行查看源碼?https://github.com/densen2014/Densen.Extensions/blob/master/Blazor/Services/LazyHeroDataService.cs
3.項目添加?Service?文件夾,添加?ImportExportsService.cs?文件
using Magicodes.ExporterAndImporter.Core;
using Magicodes.ExporterAndImporter.Excel;
using Magicodes.ExporterAndImporter.Html;
using Magicodes.ExporterAndImporter.Pdf;
using Magicodes.ExporterAndImporter.Word;
namespace Blazor100.Service
{
? ? /// <summary>
? ? /// 通用導(dǎo)入導(dǎo)出服務(wù)類
? ? /// </summary>
? ? public class ImportExportsService
? ? {
? ? ? ? public enum ExportType
? ? ? ? {
? ? ? ? ? ? Excel,
? ? ? ? ? ? Pdf,
? ? ? ? ? ? Word,
? ? ? ? ? ? Html
? ? ? ? }
? ? ? ? public async Task<string> ExportToExcel<T>(string filePath, List<T>? items = null, ExportType exportType = ExportType.Excel) where T : class, new()
? ? ? ? {
? ? ? ? ? ? switch (exportType)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? case ExportType.Pdf:
? ? ? ? ? ? ? ? ? ? var exporterPdf = new PdfExporter();
? ? ? ? ? ? ? ? ? ? items = items ?? new List<T>();
? ? ? ? ? ? ? ? ? ? var resultPdf = await exporterPdf.ExportListByTemplate(filePath + ".pdf", items);
? ? ? ? ? ? ? ? ? ? return resultPdf.FileName;
? ? ? ? ? ? ? ? case ExportType.Word:
? ? ? ? ? ? ? ? ? ? var exporterWord = new WordExporter();
? ? ? ? ? ? ? ? ? ? items = items ?? new List<T>();
? ? ? ? ? ? ? ? ? ? var resultWord = await exporterWord.ExportListByTemplate(filePath + ".docx", items);
? ? ? ? ? ? ? ? ? ? return resultWord.FileName;
? ? ? ? ? ? ? ? case ExportType.Html:
? ? ? ? ? ? ? ? ? ? var exporterHtml = new HtmlExporter();
? ? ? ? ? ? ? ? ? ? items = items ?? new List<T>();
? ? ? ? ? ? ? ? ? ? var resultHtml = await exporterHtml.ExportListByTemplate(filePath + ".html", items);
? ? ? ? ? ? ? ? ? ? return resultHtml.FileName;
? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? IExporter exporter = new ExcelExporter();
? ? ? ? ? ? ? ? ? ? items = items ?? new List<T>();
? ? ? ? ? ? ? ? ? ? var result = await exporter.Export(filePath + ".xlsx", items);
? ? ? ? ? ? ? ? ? ? return result.FileName;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? public async Task<(IEnumerable<T>? items,string error)> ImportFormExcel<T>(string filePath) where T : class, new()
? ? ? ? {
? ? ? ? ? ? IExcelImporter Importer = new ExcelImporter();
? ? ? ? ? ? var import = await Importer.Import<T>(filePath);
? ? ? ? ? ? if (import.Data == null )
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return (null, import.Exception.Message);
? ? ? ? ? ? }
? ? ? ? ? ? return (import.Data!.ToList(),"");
? ? ? ? }
? ? }
}
4.添加增加命名空間引用到?_Imports.razor?文件中
@using Blazor100.Service
@using AME.Services
5.添加ImportExportsService服務(wù)到?Program.cs?文件中
using Blazor100.Service;
builder.Services.AddTransient<ImportExportsService>();
添加封裝了Table組件的內(nèi)存數(shù)據(jù)服務(wù)LazyHeroDataService的DensenExtensions()
builder.Services.AddBootstrapBlazor();?改為
builder.Services.AddDensenExtensions();
6.數(shù)據(jù)實體類
添加導(dǎo)入導(dǎo)出特性到?Data/WeatherForecast.cs?類文件中
完整文件
using BootstrapBlazor.Components;
using FreeSql.DataAnnotations;
using Magicodes.ExporterAndImporter.Excel;
using OfficeOpenXml.Table;
using System.ComponentModel;
namespace b03sqlite.Data;
[ExcelImporter(IsLabelingError = true)]
[ExcelExporter(Name = "導(dǎo)入商品中間表", TableStyle = TableStyles.Light10, AutoFitAllColumn = true)]
[AutoGenerateClass(Searchable = true, Filterable = true, Sortable = true)]
public class WeatherForecast
{
? ? [Column(IsIdentity = true)]
? ? [DisplayName("序號")]
? ? public int ID { get; set; }
? ? [DisplayName("日期")]
? ? public DateTime Date { get; set; }
? ? public int TemperatureC { get; set; }
? ? public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
? ? public string? Summary { get; set; }
}
6.頁面文件?Pages/ImpExp.razor
@page "/impexp"
@using b03sqlite.Data
<PageTitle>導(dǎo)入導(dǎo)出</PageTitle>
<InputFile OnChange="OnChange" style="max-width:400px" class="form-control"? />
<br/>
<Table @ref="list1"
? ? ? TItem="WeatherForecast"
? ? ? IsPagination="true"
? ? ? IsStriped="true"
? ? ? IsBordered="true"
? ? ? AutoGenerateColumns="true"
? ? ? ShowSearch="true"
? ? ? ShowToolbar="true"
? ? ? ShowExtendButtons="true"
? ? ? DataService="LazyHeroDataService"
? OnSaveAsync="LazyHeroDataService!.SaveAsync"
? OnDeleteAsync="LazyHeroDataService.DeleteAsync"
? ? ? DoubleClickToEdit="@DoubleClickToEdit"
? ? ? IsExcel="@IsExcel"
? ? ? ScrollingDialogContent="true"
? ? ? EditDialogIsDraggable="true"
? ? ? EditDialogSize="Size.ExtraLarge"
? ? ? EditDialogShowMaximizeButton="true">
? ? <TableToolbarTemplate>
? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Primary" Text="自由編輯" OnClick="@IsExcelToggle" />
? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Warning" Text="隨機(jī)數(shù)據(jù)" IsAsync OnClick="@GetDatasAsync" />
? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Secondary" Text="導(dǎo)入" IsAsync OnClick="@ImportExcel" />
? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Info" Text="導(dǎo)出" IsAsync OnClickCallback="ExportAsync" />
? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Danger" Text="清空" IsAsync OnClick="EmptyAll" />
? ? ? ? <TableToolbarButton TItem="WeatherForecast" Color="Color.Success" Text="模板" IsAsync OnClick="Export模板Async" />
? ? </TableToolbarTemplate>
</Table>
7.代碼
@code{
? ? [Inject] Microsoft.AspNetCore.Hosting.IWebHostEnvironment? HostEnvironment { get; set; }
? ? [Inject] NavigationManager? navigationManager { get; set; }
? ? [Inject] ImportExportsService? importExportsService { get; set; }
? ? [Inject] ToastService? toastService { get; set; }
? ? [Inject] WeatherForecastService? ForecastService { get; set; }
? ? [Inject] LazyHeroDataService<WeatherForecast>? LazyHeroDataService { get; set; }
? ? Table<WeatherForecast>? list1 { get; set; }
? ? public bool IsExcel { get; set; }
? ? public bool DoubleClickToEdit { get; set; } = true;
? ? protected string UploadPath = "";
? ? protected string? uploadstatus;
? ? long maxFileSize = 1024 * 1024 * 15;
? ? string? tempfilename;
? ? //protected override async Task OnInitializedAsync()
? ? //{
? ? //LazyHeroDataService!.Items = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList();
? ? //}
? ? protected async Task GetDatasAsync()
? ? {
? ? ? ? LazyHeroDataService!.Items = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList();
? ? ? ? await list1!.QueryAsync();
? ? }
? ? protected override void OnAfterRender(bool firstRender)
? ? {
? ? ? ? if (firstRender)
? ? ? ? {
? ? ? ? ? ? UploadPath = Path.Combine(HostEnvironment!.WebRootPath, "Upload");
? ? ? ? ? ? if (!Directory.Exists(UploadPath)) Directory.CreateDirectory(UploadPath);
? ? ? ? }
? ? }
? ? private Task IsExcelToggle()
? ? {
? ? ? ? IsExcel = !IsExcel;
? ? ? ? DoubleClickToEdit = !IsExcel;
? ? ? ? StateHasChanged();
? ? ? ? return Task.CompletedTask;
? ? }
? ? public async Task<bool> Export模板Async()
? ? {
? ? ? ? await 模板下載();
? ? ? ? return true;
? ? }
? ? private async Task 模板下載(List<WeatherForecast>? items = null)
? ? {
? ? ? ? var ufilename = LazyHeroDataService!.Items == null ? "模板" : "新數(shù)據(jù)";
? ? ? ? var sFileName = ufilename + ".xlsx";
? ? ? ? var filename = Path.Combine(UploadPath, ufilename);
? ? ? ? await importExportsService!.ExportToExcel(filename, items);
? ? ? ? toastService?.Success("提示", ufilename + "已生成");
? ? ? ? //* 流化到前端處理也可以,不一定要用文件形式下載.
? ? ? ? navigationManager?.NavigateTo($"Upload/{sFileName}", true);
? ? ? ? //下載后清除文件
? ? ? ? _ = Task.Run(() =>
? ? ? ? {
? ? ? ? ? ? Thread.Sleep(5000);
? ? ? ? ? ? System.IO.File.Delete(filename);
? ? ? ? });
? ? }
? ? public async Task<bool> ExportAsync(IEnumerable<WeatherForecast> Items)
? ? {
? ? ? ? await 模板下載(LazyHeroDataService!.Items);
? ? ? ? return true;
? ? }
? ? public async Task<bool> EmptyAll()
? ? {
? ? ? ? LazyHeroDataService!.Items = new List<WeatherForecast>();
? ? ? ? await toastService!.Show(new ToastOption()
? ? ? ? {
? ? ? ? ? ? Category = ToastCategory.Success,
? ? ? ? ? ? Title = "提示",
? ? ? ? ? ? Content = "已清空數(shù)據(jù)",
? ? ? ? });
? ? ? ? await list1!.QueryAsync();
? ? ? ? return true;
? ? }
? ? private async Task ImportExcel()
? ? {
? ? ? ? if (string.IsNullOrEmpty(tempfilename))
? ? ? ? {
? ? ? ? ? ? toastService?.Error("提示", "請正確選擇文件上傳");
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? var option = new ToastOption()
? ? ? ? {
? ? ? ? ? ? Category = ToastCategory.Information,
? ? ? ? ? ? Title = "提示",
? ? ? ? ? ? Content = "導(dǎo)入文件中,請稍等片刻...",
? ? ? ? ? ? IsAutoHide = false
? ? ? ? };
? ? ? ? // 彈出 Toast
? ? ? ? await toastService!.Show(option);
? ? ? ? await Task.Delay(100);
? ? ? ? // 開啟后臺進(jìn)程進(jìn)行數(shù)據(jù)處理
? ? ? ? var isSuccess= await MockImportExcel();
? ? ? ? // 關(guān)閉 option 相關(guān)聯(lián)的彈窗
? ? ? ? await option.Close();
? ? ? ? // 彈窗告知下載完畢
? ? ? ? await toastService.Show(new ToastOption()
? ? ? ? {
? ? ? ? ? ? Category = isSuccess? ToastCategory.Success : ToastCategory.Error,
? ? ? ? ? ? Title = "提示",
? ? ? ? ? ? Content = isSuccess ? "操作成功,請檢查數(shù)據(jù)":"出現(xiàn)錯誤,請重試導(dǎo)入或者上傳",
? ? ? ? ? ? IsAutoHide = false
? ? ? ? });
? ? ? ? await list1!.QueryAsync();
? ? }
? ? private async Task<bool> MockImportExcel()
? ? {
? ? ? ? var items_temp = await importExportsService!.ImportFormExcel<WeatherForecast>(tempfilename!);
? ? ? ? if (items_temp.items == null)
? ? ? ? {
? ? ? ? ? ? toastService?.Error("提示", "文件導(dǎo)入失敗: "+ items_temp.error);
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? //items = SmartCombine(items_temp, items).ToList(); 新數(shù)據(jù)和老數(shù)據(jù)合并處理,略100字
? ? ? ? LazyHeroDataService!.Items = items_temp!.items.ToList();
? ? ? ? return true;
? ? }
? ? protected async Task OnChange(InputFileChangeEventArgs e)
? ? {
? ? ? ? if (e.File == null) return;
? ? ? ? tempfilename = Path.Combine(UploadPath, e.File.Name);
? ? ? ? await using FileStream fs = new(tempfilename, FileMode.Create);
? ? ? ? using var stream = e.File.OpenReadStream(maxFileSize);
? ? ? ? await stream.CopyToAsync(fs);
? ? ? ? //正式工程此處是回調(diào),簡化版必須InvokeAsync一下,自由發(fā)揮
? ? ? ? _ = Task.Run(async () => await InvokeAsync(async () => await ImportExcel()));
? ? }
}
8.試試Index.razor添加Tab組件看看效果
<Tab>
? ? <TabItem Text="導(dǎo)入導(dǎo)出">
? ? ? ? <ImpExp />
? ? </TabItem>
? ? <TabItem Text="數(shù)據(jù)維護(hù)">
? ? ? ... 原始頁面內(nèi)容
? ? </TabItem>
</Tab>
9.運(yùn)行逐一測試功能
點擊[隨機(jī)數(shù)據(jù)] 生成數(shù)據(jù)
[編輯][添加][刪除]數(shù)據(jù)
[導(dǎo)出]現(xiàn)在表格數(shù)據(jù)
[清空]數(shù)據(jù)
[選擇文件]上傳并導(dǎo)入
[清空]數(shù)據(jù)后再選擇[導(dǎo)入]
[自由編輯]類似Excel模式編輯表格
[導(dǎo)出PDF] 自行擴(kuò)展 importExportsService.ExportToExcel(filename, items,ExportType.Pdf);
[導(dǎo)出Word] 自行擴(kuò)展 importExportsService.ExportToExcel(filename, items,ExportType.Word);
[導(dǎo)出Html] 自行擴(kuò)展 importExportsService.ExportToExcel(filename, items,ExportType.Html);
項目源碼
關(guān)聯(lián)項目
FreeSql QQ群:4336577(已滿)瓤摧、8578575(已滿)该肴、52508226(在線)
BA & Blazor QQ群:795206915宪拥、675147445
知識共享許可協(xié)議
本作品采用?知識共享署名-非商業(yè)性使用-相同方式共享 4.0 國際許可協(xié)議?進(jìn)行許可。歡迎轉(zhuǎn)載戈轿、使用、重新發(fā)布,但務(wù)必保留文章署名AlexChow(包含鏈接:?https://github.com/densen2014?)面褐,不得用于商業(yè)目的,基于本文修改后的作品務(wù)必以相同的許可發(fā)布取胎。如有任何疑問展哭,請與我聯(lián)系?。
AlexChow