日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

.NET Core一行代碼導(dǎo)入導(dǎo)出Excel生成Word

 蘭亭文藝 2019-06-21

作者:holdengong

鏈接:https://www.cnblogs.com/holdengong/p/10889838.html

簡介

Excel和Word操作在開發(fā)過程中經(jīng)常需要使用,這類工作不涉及到核心業(yè)務(wù),但又往往不可缺少。以往的開發(fā)方式在業(yè)務(wù)代碼中直接引入NPOI、Aspose或者其他第三方庫,工作繁瑣,耗時(shí)多,擴(kuò)展性差——比如基礎(chǔ)庫由NPOI修改為EPPlus,意味著業(yè)務(wù)代碼需要全部修改。

由于工作需要,我在之前版本的基礎(chǔ)上,封裝了OfficeService,目的是最大化節(jié)省導(dǎo)入導(dǎo)出這種非核心功能開發(fā)時(shí)間,專注于業(yè)務(wù)實(shí)現(xiàn),并且業(yè)務(wù)端與底層基礎(chǔ)組件完全解耦,即業(yè)務(wù)端完全不需要知道底層使用的是什么基礎(chǔ)庫,使得重構(gòu)代價(jià)大大降低。

EasyOffice提供了

  • Excel導(dǎo)入:通過對(duì)模板類標(biāo)記特性自動(dòng)校驗(yàn)數(shù)據(jù)(后期計(jì)劃支持FluentApi,即傳參決定校驗(yàn)行為),并將有效數(shù)據(jù)轉(zhuǎn)換為指定類型,業(yè)務(wù)端只在拿到正確和錯(cuò)誤數(shù)據(jù)后決定如何處理;

  • Excel導(dǎo)出:通過對(duì)模板類標(biāo)記特性自動(dòng)渲染樣式(后期計(jì)劃支持FluentApi,即傳參決定導(dǎo)出行為);

  • Word根據(jù)模板生成:支持使用文本和圖片替換,占位符只需定義模板類,制作Word模板,一行代碼導(dǎo)出docx文檔(后期計(jì)劃支持轉(zhuǎn)換為pdf);

  • Word根據(jù)Table母版生成:只需定義模板類,制作表格模板,傳入數(shù)據(jù),服務(wù)會(huì)根據(jù)數(shù)據(jù)條數(shù)自動(dòng)復(fù)制表格母版,并填充數(shù)據(jù);

  • Word從空白創(chuàng)建等功能:特別復(fù)雜的Word導(dǎo)出任務(wù),支持從空白創(chuàng)建;

EasyOffice底層庫目前使用NPOI,因此是完全免費(fèi)的。

通過IExcelImportProvider等Provider接口實(shí)現(xiàn)了底層庫與實(shí)現(xiàn)的解耦,后期如果需要切換比如Excel導(dǎo)入的基礎(chǔ)庫為EPPlus,只需要提供IExcelImportProvider接口的EPPlus實(shí)現(xiàn),并且修改依賴注入代碼即可。

依賴注入

提供了.NET Core自帶ServiceCollection注入和Autofac注入

// Autofac注入Office基礎(chǔ)服務(wù)
builder.AddOffice(new OfficeOptions());

//.NET Core自帶ServiceCollection注入
services.AddOffice(new OfficeOptions());

IExcelImportService - Excel通用導(dǎo)入

定義Excel模板類

public class Car
{
[ColName('車牌號(hào)')] //對(duì)應(yīng)Excel列名
[Required] //校驗(yàn)必填
[Regex(RegexConstant.CAR_CODE_REGEX)] //正則表達(dá)式校驗(yàn),RegexConstant預(yù)置了一些常用的正則表達(dá)式,也可以自定義
[Duplication] //校驗(yàn)?zāi)0孱愒摿袛?shù)據(jù)是否重復(fù)
public string CarCode { get; set; }

[ColName('手機(jī)號(hào)')]
[Regex(RegexConstant.MOBILE_CHINA_REGEX)]
public string Mobile { get; set; }

[ColName('身份證號(hào)')]
[Regex(RegexConstant.IDENTITY_NUMBER_REGEX)]
public string IdentityNumber { get; set; }

[ColName('姓名')]
[MaxLength(10)] //最大長度校驗(yàn)
public string Name { get; set; }

[ColName('性別')]
[Regex(RegexConstant.GENDER_REGEX)]
public GenderEnum Gender { get; set; }

[ColName('注冊(cè)日期')]
[DateTime] //日期校驗(yàn)
public DateTime RegisterDate { get; set; }

[ColName('年齡')]
[Range(0, 150)] //數(shù)值范圍校驗(yàn)
public int Age { get; set; }
}

校驗(yàn)數(shù)據(jù)

var _rows = _excelImportService.ValidateAsync<ExcelCarTemplateDTO>(new ImportOption()
{
FileUrl = fileUrl, //Excel文件絕對(duì)地址
DataRowStartIndex = 1, //數(shù)據(jù)起始行索引,默認(rèn)1第二行
HeaderRowIndex = 0, //表頭起始行索引,默認(rèn)0第一行
MappingDictionary = null, //映射字典,可以將模板類與Excel列重新映射, 默認(rèn)null
SheetIndex = 0, //頁面索引,默認(rèn)0第一個(gè)頁簽
ValidateMode = ValidateModeEnum.Continue //校驗(yàn)?zāi)J?,默認(rèn)StopOnFirstFailure校驗(yàn)錯(cuò)誤后此行停止繼續(xù)校驗(yàn),Continue:校驗(yàn)錯(cuò)誤后繼續(xù)校驗(yàn)
}).Result;

//得到錯(cuò)誤行
var errorDatas = _rows.Where(x => !x.IsValid);
//錯(cuò)誤行業(yè)務(wù)處理

//將有效數(shù)據(jù)行轉(zhuǎn)換為指定類型
var validDatas = _rows.Where(x=>x.IsValid).FastConvert<ExcelCarTemplateDTO>();

//正確數(shù)據(jù)業(yè)務(wù)處理

轉(zhuǎn)換為DataTable

var dt = _excelImportService.ToTableAsync<ExcelCarTemplateDTO> //模板類型
(
fileUrl, //文件絕對(duì)地址
0, //頁簽索引,默認(rèn)0
0, //表頭行索引,默認(rèn)0
1, //數(shù)據(jù)行索引,默認(rèn)1
-1); //讀取多少條數(shù)據(jù),默認(rèn)-1全部
IExcelExportService - 通用Excel導(dǎo)出服務(wù)

IExcelExportService - 通用Excel導(dǎo)出服務(wù)

定義導(dǎo)出模板類

[Header(Color = ColorEnum.BRIGHT_GREEN, FontSize = 22, IsBold = true)] //表頭樣式
[WrapText] //自動(dòng)換行
public class ExcelCarTemplateDTO
{
[ColName('車牌號(hào)')]
[MergeCols] //相同數(shù)據(jù)自動(dòng)合并單元格
public string CarCode { get; set; }

[ColName('手機(jī)號(hào)')]
public string Mobile { get; set; }

[ColName('身份證號(hào)')]
public string IdentityNumber { get; set; }

[ColName('姓名')]
public string Name { get; set; }

[ColName('性別')]
public GenderEnum Gender { get; set; }

[ColName('注冊(cè)日期')]
public DateTime RegisterDate { get; set; }

[ColName('年齡')]
public int Age { get; set; }

導(dǎo)出Excel

var bytes = await _excelExportService.ExportAsync(new ExportOption<ExcelCarTemplateDTO>()
{
Data = list,
DataRowStartIndex = 1, //數(shù)據(jù)行起始索引,默認(rèn)1
ExcelType = Bayantu.Extensions.Office.Enums.ExcelTypeEnum.XLS,//導(dǎo)出Excel類型,默認(rèn)xls
HeaderRowIndex = 0, //表頭行索引,默認(rèn)0
SheetName = 'sheet1' //頁簽名稱,默認(rèn)sheet1
});

File.WriteAllBytes(@'c: est.xls', bytes);

IExcelImportSolutionService - Excel導(dǎo)入解決方案服務(wù)(與前端控件配套的完整解決方案,可忽略)

首先定義模板類,參考通用Excel導(dǎo)入

//獲取默認(rèn)導(dǎo)入模板
var templateBytes = await _excelImportSolutionService.GetImportTemplateAsync<DemoTemplateDTO>();

//獲取導(dǎo)入配置
var importConfig = await _excelImportSolutionService.GetImportConfigAsync<DemoTemplateDTO>('uploadUrl','templateUrl');
//獲取預(yù)覽數(shù)據(jù)
var previewData = await _excelImportSolutionService.GetFileHeadersAndRowsAsync<DemoTemplateDTO>('fileUrl');
//導(dǎo)入
var importOption = new ImportOption()
{
FileUrl = 'fileUrl',
ValidateMode = ValidateModeEnum.Continue
};
object importSetData = new object(); //前端傳過來的映射數(shù)據(jù)
var importResult = await _excelImportSolutionService.ImportAsync<DemoTemplateDTO>
(importOption
, importSetData
, BusinessAction //業(yè)務(wù)方法委托
, CustomValidate //自定義校驗(yàn)委托
);
//獲取導(dǎo)入錯(cuò)誤消息
var errorMsg = await _excelImportSolutionService.ExportErrorMsgAsync(importResult.Tag);

IWordExportService - Word通用導(dǎo)出服務(wù)

CreateFromTemplateAsync - 根據(jù)模板生成Word

//step1 - 定義模板類
public class WordCarTemplateDTO
{
//默認(rèn)占位符為{PropertyName}
public string OwnerName { get; set; }

[Placeholder('{Car_Type Car Type}')] //重寫占位符
public string CarType { get; set; }

//使用Picture或IEnumerable<Picture>類型可以將占位符替換為圖片
public IEnumerable<Picture> CarPictures { get; set; }

public Picture CarLicense { get; set; }
}

//step2 - 制作word模板
//step3 - 導(dǎo)出word
string templateUrl = @'c: emplate.docx';
WordCarTemplateDTO car = new WordCarTemplateDTO()
{
OwnerName = '劉德華',
CarType = '豪華型賓利',
CarPictures = new List<Picture>() {
new Picture()
{
PictureUrl = pic1, //圖片絕對(duì)地址,如果設(shè)置了PictureData此項(xiàng)不生效
FileName = '圖片1',//文件名稱
Height = 10,//圖片高度單位厘米默認(rèn)8
Width = 3,//圖片寬度單位厘米默認(rèn)14
PictureData = null,//圖片流數(shù)據(jù),優(yōu)先取這里的數(shù)據(jù),沒有則取url
PictureType = PictureTypeEnum.JPEG //圖片類型,默認(rèn)jpeg
},
new Picture(){
PictureUrl = pic2
}
},
CarLicense = new Picture { PictureUrl = pic3 }
};

var word = await _wordExportService.CreateFromTemplateAsync(templateUrl, car);
File.WriteAllBytes(@'c:ile.docx', word.WordBytes);

CreateWordFromMasterTable-根據(jù)模板表格循環(huán)生成word

//step1 - 定義模板類,參考上面
//step2 - 定義word模板,制作一個(gè)表格,填好占位符。
//step3 - 調(diào)用,如下示例,最終生成的word有兩個(gè)用戶表格
string templateurl = @'c: emplate.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:ile.docx', word.WordBytes);

CreateWordAsync - 從空白生成word

//step1 - 定義模板類,參考上面
//step2 - 定義word模板,制作一個(gè)表格,填好占位符。
//step3 - 調(diào)用,如下示例,最終生成的word有兩個(gè)用戶表格
string templateurl = @'c: emplate.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:ile.docx', word.WordBytes);
CreateWordAsync - 從空白生成word
[Fact]
public async Task 導(dǎo)出所有日程()
{
//準(zhǔn)備數(shù)據(jù)
var date1 = new ScheduleDate()
{
DateTimeStr = '2019年5月5日 星期八',
Addresses = new List<Address>()
};

var address1 = new Address()
{
Name = '會(huì)場一',
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 = '總經(jīng)理'
};
var speaker2 = new Speaker()
{
Name = '李四',
Position = '副總經(jīng)理'
};
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>();
//新建一個(gè)表格
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', //設(shè)置單元格顏色
Paragraphs = new List<Paragraph>()
{
//新增段落
new Paragraph()
{
//段落里面新增文本域
Run = new Run()
{
Text = date.DateTimeStr,//文本域文本,Run還可以
Color = 'red', //設(shè)置文本顏色
FontFamily = '微軟雅黑',//設(shè)置文本字體
FontSize = 12,//設(shè)置文本字號(hào)
IsBold = true,//是否粗體
Pictures = new List<Picture>()//也可以插入圖片
},
Alignment = Alignment.CENTER //段落居中
}
}
});
table.Rows.Add(rowDate);
//會(huì)場
foreach (var addr in date.Addresses)
{
//分類
foreach (var cate in addr.Categories)
{
var rowCate = new TableRow()
{
Cells = new List<TableCell>()
};

//會(huì)場名稱
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);
}

詳細(xì)例子請(qǐng)github下載代碼后自行跑單元測試查看

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

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多