10分钟做好 Bootstrap Blazor 的表格组件导出 Excel/Word/Html/Pdf
上篇: Bootstrap Blazor 实战 通用导入导出服务(Table组件)

1.新建工程
新建工程b14table
dotnet new blazorserver -o b14table
将项目添加到解决方案中:
dotnet sln add b14table/b14table.csproj
使用 nuget.org 进行 BootstrapBlazor 组件安装, FreeSql sqlite库,字体 ..
dotnet add b03sqlite package BootstrapBlazor
dotnet add b03sqlite package BootstrapBlazor.FontAwesome
dotnet add b03sqlite package FreeSql.Provider.Sqlite
dotnet add b03sqlite Densen.Extensions.BootstrapBlazor
dotnet add b03sqlite package Densen.FreeSql.Extensions.BootstrapBlazor
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 HtmlToOpenXml.dll
dotnet add b03sqlite package Haukcode.WkHtmlToPdfDotNet
[可选]BootstrapBlazor官方BootstrapBlazor.DataAcces.FreeSql包替换Densen.FreeSql.Extensions.BootstrapBlazor
2.样式表和Javascript 引用
增加主题样式表到 Pages/_Host.cshtml 文件中
删除 <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
并在下面添加两行
<link href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" rel="stylesheet">
<link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet">
添加 Javascript 引用到 Pages/_Layout.cshtml 文件中
在 <script src="_framework/blazor.server.js"></script> 之前添加
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js" asp-append-version="true"></script>
完整文件
@page "/"
@using Microsoft.AspNetCore.Components.Web
@namespace b14table.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<!-- 删掉这行 <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> !-->
<link href="css/site.css" rel="stylesheet" />
<!-- 添加下面两行 !-->
<link href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" rel="stylesheet">
<link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet">
<!-- 添加上面两行 !-->
<link href="b14table.styles.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" />
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss"></a>
</div>
<!-- 增加这行 !-->
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
3.添加增加命名空间引用到 _Imports.razor 文件中
其中 AME.Services 和 Blazor100.Service 命名空间稍后文件里用到
@using BootstrapBlazor.Components
@using AME.Services
@using Blazor100.Service
@using System.Diagnostics.CodeAnalysis
4.增加 BootstrapBlazorRoot 组件到 App.razor 文件中
<BootstrapBlazorRoot>
<Router AppAssembly="@typeof(App).Assembly">
...
</Router>
</BootstrapBlazorRoot>
5.添加 BootstrapBlazor服务/ FreeSql 数据服务/ ImportExportsService 导出服务 到 Program.cs 文件中
在 builder.Services.AddSingleton<WeatherForecastService>(); 后加入
builder.Services.AddFreeSql(option =>
{
option.UseConnectionString(FreeSql.DataType.Sqlite, "Data Source=test.db;") //也可以写到配置文件中
#if DEBUG
//开发环境:自动同步实体
.UseAutoSyncStructure(true)
.UseNoneCommandParameter(true)
//调试sql语句输出
.UseMonitorCommand(cmd => System.Console.WriteLine(cmd.CommandText))
#endif
;
});
builder.Services.AddTransient<ImportExportsService>();
//不写这句因为下面一句扩展包含了 //builder.Services.AddBootstrapBlazor();
builder.Services.AddDensenExtensions();
6. 导出服务 Service/ImportExportsService.cs
using BootstrapBlazor.Components;
using Magicodes.ExporterAndImporter.Core;
using Magicodes.ExporterAndImporter.Excel;
using Magicodes.ExporterAndImporter.Html;
using Magicodes.ExporterAndImporter.Pdf;
using Magicodes.ExporterAndImporter.Word;
namespace Blazor100.Service
{
/// <summary>
/// 通用导入导出服务类
/// </summary>
public class ImportExportsService
{
public enum ExportType
{
Excel,
Pdf,
Word,
Html
}
public async Task<string> Export<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(),"");
}
}
}
7. 数据实体类 Data/WeatherForecast.cs
using BootstrapBlazor.Components;
using FreeSql.DataAnnotations;
using Magicodes.ExporterAndImporter.Excel;
using OfficeOpenXml.Table;
using System.ComponentModel;
namespace b14table.Data;
[ExcelImporter(IsLabelingError = true)]
[ExcelExporter(Name = "导入商品中间表", 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; }
}
8. 界面和代码 Pages/Index.razor
@page "/"
@using b14table.Data
<PageTitle>Index</PageTitle>
<Tab>
<TabItem Text="导入导出">
<ImpExpII />
</TabItem>
<TabItem Text="数据维护">
<Table TItem="WeatherForecast"
IsPagination="true"
IsStriped="true"
IsBordered="true"
AutoGenerateColumns="true"
ShowSearch="true"
ShowToolbar="true"
ShowExtendButtons="true"
DoubleClickToEdit=true
ShowColumnList=true
ShowCardView=true>
</Table>
@code{
// 由于使用了FreeSql ORM 数据服务,可以直接取对象
[Inject] IFreeSql? fsql { get; set; }
[Inject] ToastService? toastService { get; set; }
//用演示服务的数据初始化数据库
[Inject] WeatherForecastService? ForecastService { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//懒的人,直接初始化一些数据用用
var res = fsql!.Select<WeatherForecast>().Count();
if (res == 0)
{
var forecasts = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList();
fsql.Insert<WeatherForecast>().AppendData(forecasts).ExecuteAffrows();
}
}
}
}
</TabItem>
</Tab>
9. 界面和代码 Pages/ImpExpII.razor
@page "/impexpii"
@using b14table.Data
@using static Blazor100.Service.ImportExportsService
<PageTitle>导入导出II</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"
ShowExportButton
OnExportAsync="ExportAsync"
PageItemsSource="new int[] {5, 20, 50, 100, 200, 500, 1000 }">
<TableToolbarTemplate>
<TableToolbarButton TItem="WeatherForecast" Color="Color.Primary" Text="自由编辑" OnClick="@IsExcelToggle" />
<TableToolbarButton TItem="WeatherForecast" Color="Color.Warning" Text="随机数据" IsAsync OnClick="@GetDatasAsync" />
<TableToolbarButton TItem="WeatherForecast" Color="Color.Secondary" Text="导入" IsAsync OnClick="@ImportExcel" />
<TableToolbarButton TItem="WeatherForecast" Color="Color.Danger" Text="清空" IsAsync OnClick="EmptyAll" />
<TableToolbarButton TItem="WeatherForecast" Color="Color.Success" Text="模板" IsAsync OnClick="Export模板Async" />
</TableToolbarTemplate>
<ExportButtonDropdownTemplate>
<h6 class="dropdown-header">当前页数据</h6>
<div class="dropdown-item" @onclick="_=>ExportExcelAsync(list1.Rows)">
<i class="fas fa-file-excel"></i>
<span>Excel</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportWordAsync(list1.Rows)">
<i class="fas fa-file-word"></i>
<span>Word</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportHtmlAsync(list1.Rows)">
<i class="fa-brands fa-html5"></i>
<span>Html</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportPDFAsync(list1.Rows)">
<i class="fas fa-file-pdf"></i>
<span>PDF</span>
</div>
<div class="dropdown-divider"></div>
<h6 class="dropdown-header">全部数据</h6>
<div class="dropdown-item" @onclick="_=>ExportExcelAsync(LazyHeroDataService!.Items)">
<i class="fas fa-file-excel"></i>
<span>Excel</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportWordAsync(LazyHeroDataService!.Items)">
<i class="fas fa-file-word"></i>
<span>Word</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportHtmlAsync(LazyHeroDataService!.Items)">
<i class="fa-brands fa-html5"></i>
<span>Html</span>
</div>
<div class="dropdown-item" @onclick="_=>ExportPDFAsync(LazyHeroDataService!.Items)">
<i class="fas fa-file-pdf"></i>
<span>PDF</span>
</div>
</ExportButtonDropdownTemplate>
</Table>
@code{
[Inject]
Microsoft.AspNetCore.Hosting.IWebHostEnvironment? HostEnvironment { get; set; }
[Inject]
[NotNull]
NavigationManager? NavigationManager { get; set; }
[Inject]
[NotNull]
ImportExportsService? ImportExportsService { get; set; }
[Inject]
[NotNull]
ToastService? ToastService { get; set; }
[Inject]
WeatherForecastService? ForecastService { get; set; }
[Inject]
[NotNull]
LazyHeroDataService<WeatherForecast>? LazyHeroDataService { get; set; }
[NotNull]
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 async Task GetDatasAsync()
{
LazyHeroDataService!.Items = (await ForecastService!.GetForecastAsync(DateTime.Now)).ToList();
await list1!.QueryAsync();
}
protected override async void OnAfterRender(bool firstRender)
{
if (firstRender)
{
UploadPath = Path.Combine(HostEnvironment!.WebRootPath, "uploads");
if (!Directory.Exists(UploadPath)) Directory.CreateDirectory(UploadPath);
await GetDatasAsync();
}
}
private Task IsExcelToggle()
{
IsExcel = !IsExcel;
DoubleClickToEdit = !IsExcel;
StateHasChanged();
return Task.CompletedTask;
}
public async Task<bool> Export模板Async()
{
await Export();
return true;
}
private async Task<bool> ExportExcelAsync(IEnumerable<WeatherForecast> items) => await ExportAutoAsync(items, ExportType.Excel);
private async Task<bool> ExportPDFAsync(IEnumerable<WeatherForecast> items) => await ExportAutoAsync(items, ExportType.Pdf);
private async Task<bool> ExportWordAsync(IEnumerable<WeatherForecast> items) => await ExportAutoAsync(items, ExportType.Word);
private async Task<bool> ExportHtmlAsync(IEnumerable<WeatherForecast> items) => await ExportAutoAsync(items, ExportType.Html);
private async Task<bool> ExportAutoAsync(IEnumerable<WeatherForecast> items, ExportType exportType = ExportType.Excel)
{
if ((items == null || !items.Any()) && (LazyHeroDataService!.Items == null || !LazyHeroDataService!.Items.Any()))
{
await ToastService.Error("提示", "无数据可导出");
return false;
}
var option = new ToastOption()
{
Category = ToastCategory.Information,
Title = "提示",
Content = $"导出正在执行,请稍等片刻...",
IsAutoHide = false
};
// 弹出 Toast
await ToastService.Show(option);
await Task.Delay(100);
// 开启后台进程进行数据处理
await Export(items?.ToList(), exportType);
// 关闭 option 相关联的弹窗
option.Close();
// 弹窗告知下载完毕
await ToastService.Show(new ToastOption()
{
Category = ToastCategory.Success,
Title = "提示",
Content = $"导出成功,请检查数据",
IsAutoHide = false
});
return true;
}
private async Task Export(List<WeatherForecast>? items=null, ExportType exportType = ExportType.Excel)
{
try
{
if (items==null || !items.Any()) items = LazyHeroDataService!.Items;
var fileName = items == null ? "模板" : typeof(WeatherForecast).Name;
var fullName = Path.Combine(UploadPath, fileName);
fullName = await ImportExportsService.Export(fullName, items, exportType);
fileName = (new System.IO.FileInfo(fullName)).Name;
ToastService?.Success("提示", fileName + "已生成");
//下载后清除文件
NavigationManager.NavigateTo($"uploads/{fileName}", true);
_ = Task.Run(() =>
{
Thread.Sleep(50000);
System.IO.File.Delete(fullName);
});
}
catch (Exception e)
{
ToastService?.Error($"导出", $"{exportType}出错,请检查. {e.Message}");
}
}
public async Task<bool> EmptyAll()
{
LazyHeroDataService!.Items = new List<WeatherForecast>();
await ToastService!.Show(new ToastOption()
{
Category = ToastCategory.Success,
Title = "提示",
Content = "已清空数据",
});
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 = "导入文件中,请稍等片刻...",
IsAutoHide = false
};
// 弹出 Toast
await ToastService!.Show(option);
await Task.Delay(100);
// 开启后台进程进行数据处理
var isSuccess= await MockImportExcel();
// 关闭 option 相关联的弹窗
option.Close();
// 弹窗告知下载完毕
await ToastService.Show(new ToastOption()
{
Category = isSuccess? ToastCategory.Success : ToastCategory.Error,
Title = "提示",
Content = isSuccess ? "操作成功,请检查数据":"出现错误,请重试导入或者上传",
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("提示", "文件导入失败: "+ items_temp.error);
return false;
}
//items = SmartCombine(items_temp, items).ToList(); 新数据和老数据合并处理,略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);
//正式工程此处是回调,简化版必须InvokeAsync一下,自由发挥
_ = Task.Run(async () => await InvokeAsync(async () => await ImportExcel()));
}
/// <summary>
/// 导出数据方法
/// </summary>
/// <param name="Items"></param>
/// <param name="opt"></param>
/// <returns></returns>
protected async Task<bool> ExportAsync(IEnumerable<WeatherForecast> Items, QueryPageOptions opt)
{
var ret = false;
ret = await ExportExcelAsync(Items);
return ret;
}
}
项目源码
关联项目
FreeSql QQ群:4336577(已满)、8578575(已满)、52508226(在线)
BA & Blazor QQ群:795206915、675147445
知识共享许可协议
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系 。
AlexChow
今日头条 | 博客园 | 知乎 | Gitee | GitHub
10分钟做好 Bootstrap Blazor 的表格组件导出 Excel/Word/Html/Pdf的更多相关文章
- 将页面中表格数据导出excel格式的文件(vue)
近期由于项目需要,需要将页面中的表格数据导出excel格式的文件,折腾了许久,在网上各种百度,虽然资料不少,但是大都不全,踩了许多坑,总算是皇天不负有心人,最后圆满解决了. 1.安装相关依赖(npm安 ...
- 【Bootstrap】 bootstrap-table表格组件
[Bootstrap-table] 顾名思义,这个组件专注于bootstrap风格的表格的设计,并且提供了很多表格的基础和进阶的功能,给我们开发前端的表格省下很多力气. 本文主要参考这位博主的系列文章 ...
- Vue项目中将table组件导出Excel表格以及打印页面内容
体验更优排版请移步原文:http://blog.kwin.wang/programming/vue-table-export-excel-and-print.html 页面中显示的table表格,经常 ...
- Vue+element UI实现表格数据导出Excel组件
介绍 这是一个可以将页面中的表格数据导出为Excel文件的功能组件,该组件一般与表格一起使用,将表格数据传给组件,然后通过点击组件按钮可将表格中的数据导出成Excel文件. 使用方法 由于封装该组件内 ...
- 前端表格数据导出excel
使用tableExport.js导出bootstrap-table表格成excel并且支持中文 1. 下载tableExport.js https://github.com/hhurz/tableEx ...
- 关于调用office com组件导出Excel
服务器环境: 环境为win2008 r2,系统为64位,程序是C#的winform.因为需要处理数据,然后生成Excel,耗时太长,就使用了多线程.winform程序是由计划任务启动,每天晚上去跑. ...
- C# 关于调用office com组件导出Excel
服务器环境: 环境为win2008 r2,系统为64位,程序是C#的winform.因为需要处理数据,然后生成Excel,耗时太长,就使用了多线程.winform程序是由计划任务启动,每天晚上去跑. ...
- 网页表格导入导出Excel
用JS实现网页表格数据导入导出excel. 首先是JS文件中的代码 (function($){ function getRows(target){ var state = $(target).data ...
- 前端 vue表格数据导出Excel 文件实现
实现思路 使用json2csv将后台json数据转化为csv格式数据 采用创建Blob(二进制大对象)的方式来存放缓存数据: 生成下载链接: 创建一个a标签,设置href和download属性 触发a ...
- C#调用NPOI组件导出Excel表格
把一个List集合的数据导出到Excel表格中 public static string RenderToExcel<T>(List<T> datas) { MemoryStr ...
随机推荐
- 插入排序算法(Java代码实现)
其它经典排序算法:https://blog.csdn.net/weixin_43304253/article/details/121209905 插入排序算法: 思路:将数据分为已经排序好的数据和未排 ...
- go-zero docker-compose搭建课件服务(四):生成Dockerfile
0.转载 go-zero docker-compose 搭建课件服务(四):生成Dockerfile并在docker-compose中启动 0.1源码地址 https://github.com/liu ...
- C++算法之旅、02 从木棒切割问题领悟二分法精髓
172.木棒切割问题 https://sunnywhy.com/problem/172 题目描述 给出n根木棒的长度,现在希望通过切割它们来得到至少k段长度相等的木棒(长度必须是整数),问这些长度相等 ...
- day05-JavaScript02
JavaScript02 8.JavaScript函数 JavaScript函数介绍 函数是由事件驱动的,或者当它被调用时,执行的可重复使用的代码 例子 <!DOCTYPE html> & ...
- vue-axios增加操作
<template> <div class="Insert"> <label for="name">名称:</labe ...
- 《ASP.NET Core技术内幕与项目实战》精简集-目录
本系列是杨中科2022年最新作品<ASP.NET Core技术内幕与项目实战>及B站配套视频(强插点赞)的精简集,是一个读书笔记.总结和提炼了主要知识点,遵守代码优先原则,以利于快速复习和 ...
- Dubbo-聊聊通信模块设计
前言 Dubbo源码阅读分享系列文章,欢迎大家关注点赞 SPI实现部分 Dubbo-SPI机制 Dubbo-Adaptive实现原理 Dubbo-Activate实现原理 Dubbo SPI-Wrap ...
- 死磕Java面试系列:深拷贝与浅拷贝的实现原理
深拷贝与浅拷贝的问题,也是面试中的常客.虽然大家都知道两者表现形式不同点在哪里,但是很少去深究其底层原理,也不知道怎么才能优雅的实现一个深拷贝.其实工作中也常常需要实现深拷贝,今天一灯就带大家一块深入 ...
- 如何开发Vite3插件构建Electron开发环境
新用户购买<Electron + Vue 3 桌面应用开发>,加小册专属微信群,参与群抽奖,送<深入浅出Electron>.<Electron实战>作者签名版. 1 ...
- 基于iNeuOS工业互联网平台的板材实时质检系统
1. 项目背景 刨花板生产线由于原料.生产工艺等原因,会有一些产品板面出现颤纹.漏砂.胶斑.胶块.大刨花.粉尘斑.板面划痕和油污等缺陷.表面缺陷会降低板材强度.影响板材外观和二次加工,给企业带来经济 ...