上一篇文章介紹了一些NPOI的基礎接口,咱們如今就來看看具體怎麼用NPOI來解析一個EXCEL。html
博主如今有這麼一堆excel須要解析數據入庫:node
固然這只是員工的簡要模板,還有不少其餘的模板。咱們能夠要求線下人員把表頭都作成像這樣的表頭,可是數據的列數與各列內容是不受咱們所控制的。那麼咱們須要的就是一個公用的方法,可以解析這一類表頭的excel數據。數據庫
既然每種表對應着一張數據庫表,字段不同,那麼咱們的方法就考慮到使用反射機制來給泛型DTO屬性賦值。具體每一個excel表的各列與DTO屬性字段的對應以及表自己信息咱們用XML文件來作配置。OK,咱們獲得下面的一個基本流程:框架
1.用戶上傳excel文件,調用uploadExcelFile()接口工具
2.uploadExcelFile()接口保存文件到指定路徑,調用excel解析工具類ImportExcel()方法,傳入泛型參數ExcelDataDTO與excel配置文件xml路徑spa
3.ImportExcel()服務首先驗證excel數據(表頭與xml是否匹配,各單元格數據格式,空格等等)設計
4.驗證經過後調用獲取數據方法,失敗值直接返回具體失敗數據(定位到每一行的某一列,並附帶具體錯誤緣由)excel
OK,那咱們先來看看excel的配置xml文件具體怎麼配置:code
1 <?xml version="1.0" encoding="utf-8" ?> 2 <module> 3 <add firstHeaderRow="2" lastHeaderRow="2" sheetCount="1"/> 4 <add headerText="姓名" propertyName="Name" dataType="System.String"/> 5 <add headerText="手機號碼" propertyName="PhoneNumber" dataType="System.String"/> 6 <add headerText="性別" propertyName="Sex" dataType="System.Boolean"/> 7 <add headerText="民族" propertyName="Nation" dataType="System.String"/> 8 <add headerText="出生日期" propertyName="Birthday" dataType="System.String"/> 9 <add headerText="身份證號碼" propertyName="Cardid" dataType="System.String"/> 10 </module>
再寫一個讀取excel配置xml文件的方法:xml
1 // 讀取XML配置信息集 2 public List<Regular> GetXMLInfo(string xmlpath) 3 { 4 var reader = new XmlTextReader(xmlpath); 5 var doc = new XmlDocument(); 6 doc.Load(reader); 7 8 var headerList = new List<Regular>(); 9 foreach (XmlNode node in doc.DocumentElement.ChildNodes) 10 { 11 var header = new Regular(); 12 13 if (node.Attributes["firstHeaderRow"] != null) 14 header.HeaderRegular.Add("firstHeaderRow", int.Parse(node.Attributes["firstHeaderRow"].Value)); 15 if (node.Attributes["lastHeaderRow"] != null) 16 header.HeaderRegular.Add("lastHeaderRow", int.Parse(node.Attributes["lastHeaderRow"].Value)); 17 if (node.Attributes["sheetCount"] != null) 18 header.HeaderRegular.Add("sheetCount", int.Parse(node.Attributes["sheetCount"].Value)); 19 20 if (node.Attributes["headerText"] != null) 21 header.HeaderText = node.Attributes["headerText"].Value; 22 if (node.Attributes["propertyName"] != null) 23 header.PropertyName = node.Attributes["propertyName"].Value; 24 if (node.Attributes["dataType"] != null) 25 header.DataType = node.Attributes["dataType"].Value; 26 27 headerList.Add(header); 28 } 29 return headerList; 30 }
其中涉及到一個咱們本身建立的規則類,Regular
1 /// <summary> 2 /// 模板規則類 3 /// </summary> 4 public class Regular 5 { 6 /// <summary> 7 /// 表頭文本 8 /// </summary> 9 public string HeaderText { set; get; } 10 11 /// <summary> 12 /// 屬性名稱 13 /// </summary> 14 public string PropertyName { set; get; } 15 16 /// <summary> 17 /// 數據類型 18 /// </summary> 19 public string DataType { set; get; } 20 21 private Dictionary<string, int> _regular = new Dictionary<string, int>(); 22 23 /// <summary> 24 /// 表頭規則 25 /// </summary> 26 public Dictionary<string, int> HeaderRegular 27 { 28 get { return _regular; } 29 set { _regular = value; } 30 } 31 }
這樣,咱們就能將一個excel的配置信息讀取出來備用。
具體上傳文件的接口就不在這兒粘貼了,之前有一篇文章介紹過wenAPI作文件上傳,地址:
http://www.cnblogs.com/csqb-511612371/p/4871574.html
咱們在文件上傳成功後的邏輯是調用服務ImportExcel,解析出excel數據到DTO,而後再將DTO映射到實體入庫。
那麼就會有這樣一段代碼:
1 var xmlName = getXml();// 本身定義的獲取配置文件名稱方法 2 var excelDataDtos = new List<ExcelDataDTO>(); 3 var result = attachmentFileService.ImportExcel(excelFilePath, xmlName, ref excelDataDtos); 4 if (result.Success) 5 {
9 foreach (var excelDataDto in excelDataDtos) 10 {
// 數據入庫 19 employeeInfoService.HR_Add_EmployeeInfo(excelDataDto); 20 }
}
ExcelDataDTO是咱們對應這個excel文件的DTO,此處簡要的直接new了,也應該是單獨服務產生(由於咱們這個方法是實現多模板上傳)。
第3行ImportExcel方法中將執行邏輯:獲取基礎配置信息->驗證excel數據->讀取excel數據
1 public UploadExcelFileResult ImportExcel(string filePath, string xmlPath, ref List<ExcelDataDTO> excelDTO) 2 { 3 // XML配置文件絕對路徑 4 var xmlFilePath = ExcelTemplateBasePath + xmlPath; 5 6 var excelImportService = new ExcelImportService(filePath, xmlFilePath); 7 var result = excelImportService.ValidateExcel(); 8 if (result.Success) 9 { 10 excelDTO = excelImportService.Import<ExcelDataDTO>(); 11 } 12 return result; 13 }
注:
1.第6行初始化excel導入服務(初始化基本配置信息)
2.第7行驗證excel數據,失敗則返回具體錯誤信息
3.驗證經過則讀取excel數據到DTO
這兒的excelImportService就涉及到整個excel解析工具了,咱們先看看整個excel解析的接口與實現文件:
其中Regular前面已經講過了,是規則集。UploadExcelFileResult則是解析返回結果,內含成功與否,總Message,文件信息,具體錯誤信息等數據:
/// <summary> /// EXCEL文件上傳檢查返回數據 /// </summary> public class UploadExcelFileResult { /// <summary> /// 是否成功 /// </summary> public bool Success { get; set; } /// <summary> /// 附帶消息 /// </summary> public string Message { get; set; } /// <summary> /// 文件基本信息 /// </summary> public FileMessage FileMessage { get; set; } /// <summary> /// 解析失敗後錯誤位置定位信息 /// </summary> public List<ExcelFileErrorPosition> ExcelFileErrorPositions { get; set; } } public class FileMessage { /// <summary> /// 上傳文件名稱 /// </summary> public string FileName { get; set; } /// <summary> /// 文件大小 /// </summary> public int Length { get; set; } /// <summary> /// 文件類型 /// </summary> public string Type { get; set; } } public class ExcelFileErrorPosition { /// <summary> /// 錯誤行 /// </summary> public int RowIndex { get; set; } /// <summary> /// 錯誤列集 /// </summary> public List<int> CellIndex { get; set; } /// <summary> /// 錯誤列具體錯誤信息 /// </summary> public List<string> ErrorMessage { get; set; } /// <summary> /// 錯誤行數據 /// </summary> public List<string> RowContent { get; set; } }
而後咱們來看具體的三個接口:
1.IExcelParseBaseService接口是最基礎服務接口,裏面包含全部須要用到的抽象方法:
1 /// <summary> 2 /// EXCEL解析基本服務接口 3 /// </summary> 4 public interface IExcelParseBaseService 5 { 6 /// <summary> 7 /// 檢查單元格數據類型 8 /// </summary> 9 /// <param name="cellType">類型</param> 10 /// <param name="cellValue">單元格值</param> 11 /// <returns>類型是否出錯</returns> 12 bool CheckDataType(string cellType, string cellValue); 13 14 /// <summary> 15 /// 檢查單元格數據是否爲空 16 /// </summary> 17 /// <param name="cellValue">單元格值</param> 18 /// <param name="nullcount">行空值計數器</param> 19 /// <returns>數據是否爲空</returns> 20 bool CheckNull(string cellValue, ref int nullcount); 21 22 /// <summary> 23 /// 去除數據空格 24 /// </summary> 25 /// <param name="cellValue">單元格值</param> 26 void ReplaceSpace(ref string cellValue); 27 28 /// <summary> 29 /// 判斷當前單元格是否爲合併單元格 30 /// </summary> 31 /// <param name="cellIndex">單元格所在列序號</param> 32 /// <param name="rowIndex">單元格所在行序號</param> 33 /// <param name="sheet">EXCEL工做表</param> 34 /// <returns>合併單元格爲true</returns> 35 bool IsMergedRegionCell(int cellIndex, int rowIndex, ISheet sheet, ref int firstRegionRow); 36 37 /// <summary> 38 /// 讀取EXCEL XML配置信息集 39 /// </summary> 40 /// <param name="xmlpath">xml文件路徑</param> 41 /// <returns></returns> 42 List<Regular> GetXMLInfo(string xmlpath); 43 }
它的實現類是抽象類ExcelParseBaseService
2.IExcelAnalyzeService接口是excel解析的核心服務,實現對excel的操做
1 /// <summary> 2 /// EXCEL 解析基礎服務 3 /// </summary> 4 public interface IExcelAnalyzeService 5 { 6 /// <summary> 7 /// 獲取指定excel文件版本 8 /// </summary> 9 /// <param name="fileName">EXCEL文件名稱</param> 10 /// <returns></returns> 11 int GetExcelEdition(string fileName); 12 13 /// <summary> 14 /// 根據EXCEL版本建立WorkBook 15 /// </summary> 16 /// <param name="edition">EXCEL版本</param> 17 /// <param name="excelFileStream">EXCEL文件</param> 18 /// <returns>excel文件對應workbook</returns> 19 IWorkbook CreateWorkBook(int edition, Stream excelFileStream); 20 21 /// <summary> 22 /// 解析並檢查EXCEL表頭數據 23 /// </summary> 24 /// <param name="sheet"></param> 25 /// <param name="uploadExcelFileResult"></param> 26 /// <param name="list"></param> 27 /// <returns></returns> 28 Dictionary<int, string> GetExcelHeaders(ISheet sheet, ref UploadExcelFileResult uploadExcelFileResult, 29 List<Regular> list); 30 31 /// <summary> 32 /// 讀取EXCEL數據 33 /// </summary> 34 /// <typeparam name="TableDTO">數據對象</typeparam> 35 /// <param name="sheet">工做簿對應工做表</param> 36 /// <param name="sheetName">excel工做表名稱</param> 37 /// <param name="list">該excel規則集</param> 38 /// <param name="dict">表頭字典</param> 39 /// <param name="rowCount">總數據行數</param> 40 /// <returns>解析後的Excel數據集</returns> 41 List<TableDTO> GetExcelDatas<TableDTO>(ISheet sheet, string sheetName, List<Regular> list, 42 Dictionary<int, string> dict, int rowCount); 43 44 /// <summary> 45 /// 檢查excel數據 46 /// </summary> 47 /// <param name="sheet">excel工做表</param> 48 /// <param name="list">規則集</param> 49 /// <param name="dict">表頭</param> 50 /// <param name="rowCount">總數據行數</param> 51 /// <returns>檢查結果</returns> 52 UploadExcelFileResult CheckExcelDatasEnableNull(ISheet sheet, List<Regular> list, Dictionary<int, string> dict,int rowCount); 53 }
它的實現類是ExcelAnalyzeService,也是抽象類並繼承於Base服務ExcelParseBaseService
3.IExcelImportService接口就是對外暴漏的excel解析工具類的接口,只含兩個方法:驗證和讀取;
1 /// <summary> 2 /// Excel 導入基礎服務接口 3 /// </summary> 4 public interface IExcelImportService 5 { 6 /// <summary> 7 /// 綜合驗證Excel表格符合性 8 /// </summary> 9 /// <returns></returns> 10 UploadExcelFileResult ValidateExcel(); 11 12 /// <summary> 13 /// 導入EXCEL文件 14 /// </summary> 15 /// <typeparam name="TableDTO">數據對象DTO</typeparam> 16 /// <returns>EXCEL數據集合</returns> 17 List<TableDTO> Import<TableDTO>(); 18 }
它的實現是ExcelImportService,繼承於抽象類ExcelAnalyzeService。是咱們外部調用excel工具的入口
具體各個類方法的實現,下一篇文章再繼續貼代碼。
本篇文章主要講述了經過配置xml文件解析多模板excel表格數據的設計流程與主要框架,附帶部分規則代碼。具體工具內接口方法實現,請關注下一篇文章。
原創文章,代碼都是從本身項目裏貼出來的。轉載請註明出處哦,親~~~