EasyOffice-.NetCore一行代码导入导出Excel,生成Word

    xiaoxiao2021-04-16  214

    Excel和Word操作在开发过程中经常需要使用,这类工作不涉及到核心业务,但又往往不可缺少。以往的开发方式在业务代码中直接引入NPOI、Aspose或者其他第三方库,工作繁琐,耗时多,扩展性差——比如基础库由NPOI修改为EPPlus,意味着业务代码需要全部修改。由于工作需要,我在之前版本的基础上,封装了OfficeService,目的是最大化节省导入导出这种非核心功能开发时间,专注于业务实现,并且业务端与底层基础组件完全解耦,即业务端完全不需要知道底层使用的是什么基础库,使得重构代价大大降低。

    EasyOffice提供了

    Excel导入:通过对模板类标记特性自动校验数据(后期计划支持FluentApi,即传参决定校验行为),并将有效数据转换为指定类型,业务端只在拿到正确和错误数据后决定如何处理;

    Excel导出:通过对模板类标记特性自动渲染样式(后期计划支持FluentApi,即传参决定导出行为);

    Word根据模板生成:支持使用文本和图片替换,占位符只需定义模板类,制作Word模板,一行代码导出docx文档(后期计划支持转换为pdf);

    Word根据Table母版生成:只需定义模板类,制作表格模板,传入数据,服务会根据数据条数自动复制表格母版,并填充数据;

    Word从空白创建等功能:特别复杂的Word导出任务,支持从空白创建;

    EasyOffice底层库目前使用NPOI,因此是完全免费的。通过IExcelImportProvider等Provider接口实现了底层库与实现的解耦,后期如果需要切换比如Excel导入的基础库为EPPlus,只需要提供IExcelImportProvider接口的EPPlus实现,并且修改依赖注入代码即可。

    提供了.net core自带ServiceCollection注入和Autofac注入

    builder.AddOffice(new OfficeOptions());services.AddOffice(new OfficeOptions());

    定义Excel模板类

    public class Car { [ColName("车牌号")] [Required] [Regex(RegexConstant.CAR_CODE_REGEX)] [Duplication] public string CarCode { get; set; } [ColName("手机号")] [Regex(RegexConstant.MOBILE_CHINA_REGEX)]public string Mobile { get; set; } [ColName("身份证号")] [Regex(RegexConstant.IDENTITY_NUMBER_REGEX)]public string IdentityNumber { get; set; } [ColName("姓名")] [MaxLength(10)] public string Name { get; set; } [ColName("性别")] [Regex(RegexConstant.GENDER_REGEX)]public GenderEnum Gender { get; set; } [ColName("注册日期")] [DateTime] public DateTime RegisterDate { get; set; } [ColName("年龄")] [Range(0, 150)] public int Age { get; set; } }

    校验数据

    var _rows = _excelImportService.ValidateAsync<ExcelCarTemplateDTO>(new ImportOption() { FileUrl = fileUrl, DataRowStartIndex = 1, HeaderRowIndex = 0, MappingDictionary = null, SheetIndex = 0, ValidateMode = ValidateModeEnum.Continue }).Result; var errorDatas = _rows.Where(x => !x.IsValid); var validDatas = _rows.Where(x=>x.IsValid).FastConvert<ExcelCarTemplateDTO>();

    转换为DataTable

    var dt = _excelImportService.ToTableAsync<ExcelCarTemplateDTO> ( fileUrl, 0, 0, 1, -1);

    定义导出模板类

    [Header(Color = ColorEnum.BRIGHT_GREEN, FontSize = 22, IsBold = true)] [WrapText] public class ExcelCarTemplateDTO { [ColName("车牌号")] [MergeCols] public string CarCode { get; set; } [ColName("手机号")]public string Mobile { get; set; } [ColName("身份证号")]public string IdentityNumber { get; set; } [ColName("姓名")]public string Name { get; set; } [ColName("性别")]public GenderEnum Gender { get; set; } [ColName("注册日期")]public DateTime RegisterDate { get; set; } [ColName("年龄")]public int Age { get; set; }

    导出Excel

    var bytes = await _excelExportService.ExportAsync(new ExportOption<ExcelCarTemplateDTO>() { Data = list, DataRowStartIndex = 1, ExcelType = Bayantu.Extensions.Office.Enums.ExcelTypeEnum.XLS, HeaderRowIndex = 0, SheetName = "sheet1" }); File.WriteAllBytes(@"c:\test.xls", bytes);

    首先定义模板类,参考通用Excel导入

    var templateBytes = await _excelImportSolutionService.GetImportTemplateAsync<DemoTemplateDTO>();var importConfig = await _excelImportSolutionService.GetImportConfigAsync<DemoTemplateDTO>("uploadUrl","templateUrl");var previewData = await _excelImportSolutionService.GetFileHeadersAndRowsAsync<DemoTemplateDTO>("fileUrl");var importOption = new ImportOption() { FileUrl = "fileUrl", ValidateMode = ValidateModeEnum.Continue };object importSetData = new object(); var importResult = await _excelImportSolutionService.ImportAsync<DemoTemplateDTO> (importOption , importSetData , BusinessAction , CustomValidate );var errorMsg = await _excelImportSolutionService.ExportErrorMsgAsync(importResult.Tag);

    CreateFromTemplateAsync - 根据模板生成Word

    public class WordCarTemplateDTO {public string OwnerName { get; set; } [Placeholder("{Car_Type Car Type}")] public string CarType { get; set; }public IEnumerable<Picture> CarPictures { get; set; }public Picture CarLicense { get; set; } }string templateUrl = @"c:\template.docx";WordCarTemplateDTO car = new WordCarTemplateDTO(){ OwnerName = "刘德华", CarType = "豪华型宾利", CarPictures = new List<Picture>() {new Picture() { PictureUrl = pic1, FileName = "图片1", Height = 10, Width = 3, PictureData = null, PictureType = PictureTypeEnum.JPEG },new Picture(){ PictureUrl = pic2 } }, CarLicense = new Picture { PictureUrl = pic3 }};var word = await _wordExportService.CreateFromTemplateAsync(templateUrl, car);File.WriteAllBytes(@"c:\file.docx", word.WordBytes);

    CreateWordFromMasterTable-根据模板表格循环生成word

    string templateurl = @"c:\template.docx";var user1 = new UserInfoDTO() { Name = "张三", Age = 15, Gender = "男", Remarks = "简介简介" };var user2 = new UserInfoDTO() { Name = "李四", Age = 20, Gender = "女", Remarks = "简介简介简介" };var datas = new List<UserInfoDTO>() { user1, user2 };for (int i = 0; i < 10; i++) { datas.Add(user1); datas.Add(user2); }var word = await _wordExportService.CreateFromMasterTableAsync(templateurl, datas); File.WriteAllBytes(@"c:\file.docx", word.WordBytes);

    CreateWordAsync - 从空白生成word

    [Fact] public async Task 导出所有日程() {var date1 = new ScheduleDate() { DateTimeStr = "2019年5月5日 星期八", Addresses = new List<Address>() };var address1 = new Address() { Name = "会场一", Categories = new List<Category>() };var cate1 = new Category() { Name = "分类1", Schedules = new List<Schedule>() };var schedule1 = new Schedule() { Name = "日程1", TimeString = "上午9:00 - 上午12:00", Speakers = new List<Speaker>() };var schedule2 = new Schedule() { Name = "日程2", TimeString = "下午13:00 - 下午14:00", Speakers = new List<Speaker>() };var speaker1 = new Speaker() { Name = "张三", Position = "总经理" };var speaker2 = new Speaker() { Name = "李四", Position = "副总经理" }; schedule1.Speakers.Add(speaker1); schedule1.Speakers.Add(speaker2); cate1.Schedules.Add(schedule1); cate1.Schedules.Add(schedule2); address1.Categories.Add(cate1); date1.Addresses.Add(address1);var dates = new List<ScheduleDate>() { date1,date1,date1 };var tables = new List<Table>();var table = new Table() { Rows = new List<TableRow>() }; foreach (var date in dates) {var rowDate = new TableRow() { Cells = new List<TableCell>() }; rowDate.Cells.Add(new TableCell() { Color = "lightblue", Paragraphs = new List<Paragraph>() { new Paragraph() { Run = new Run() { Text = date.DateTimeStr, Color = "red", FontFamily = "微软雅黑", FontSize = 12, IsBold = true, Pictures = new List<Picture>() }, Alignment = Alignment.CENTER } } }); table.Rows.Add(rowDate); foreach (var addr in date.Addresses) { foreach (var cate in addr.Categories) {var rowCate = new TableRow() { Cells = new List<TableCell>() }; rowCate.Cells.Add(new TableCell() { Paragraphs = new List<Paragraph>{ new Paragraph() { Run = new Run() { Text = addr.Name, } } } }); rowCate.Cells.Add(new TableCell() { Paragraphs = new List<Paragraph>(){ new Paragraph() { Run = new Run() { Text = cate.Name, } } } }); table.Rows.Add(rowCate); foreach (var sche in cate.Schedules) {var rowSche = new TableRow() { Cells = new List<TableCell>() };var scheCell = new TableCell() { Paragraphs = new List<Paragraph>() {new Paragraph() { Run = new Run() { Text = sche.Name } }, {new Paragraph() { Run = new Run() { Text = sche.TimeString } } } } }; foreach (var speaker in sche.Speakers) { scheCell.Paragraphs.Add(new Paragraph() { Run = new Run() { Text = $"{speaker.Position}:{speaker.Name}" } }); } rowSche.Cells.Add(scheCell); table.Rows.Add(rowSche); } } } } tables.Add(table);var word = await _wordExportService.CreateWordAsync(tables); File.WriteAllBytes(fileUrl, word.WordBytes); }

    github地址:https://github.com/holdengong/EasyOffice

    水平有限,如果有bug欢迎提issue;如果本项目对您略有帮助,请帮忙Start和推荐,谢谢。

    原文地址:https://www.cnblogs.com/holdengong/p/10889838.html

    .NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com 


    最新回复(0)