上一篇文章介绍了一些NPOI的基础接口,我们现在就来看看具体怎么用NPOI来解析一个EXCEL。
博主现在有这么一堆excel需要解析数据入库:
当然这只是员工的简要模板,还有很多其他的模板。我们可以要求线下人员把表头都做成像这样的表头,但是数据的列数与各列内容是不受我们所控制的。那么我们需要的就是一个公用的方法,能够解析这一类表头的excel数据。
既然每种表对应着一张数据库表,字段不一样,那么我们的方法就考虑到使用反射机制来给泛型DTO属性赋值。具体每个excel表的各列与DTO属性字段的对应以及表本身信息我们用XML文件来做配置。OK,我们得到下面的一个基本流程:
1.用户上传excel文件,调用uploadExcelFile()接口
2.uploadExcelFile()接口保存文件到指定路径,调用excel解析工具类ImportExcel()方法,传入泛型参数ExcelDataDTO与excel配置文件xml路径
3.ImportExcel()服务首先验证excel数据(表头与xml是否匹配,各单元格数据格式,空格等等)
4.验证通过后调用获取数据方法,失败值直接返回具体失败数据(定位到每一行的某一列,并附带具体错误原因)
OK,那我们先来看看excel的配置xml文件具体怎么配置:
1 23 4 5 6 7 8 9 10
再写一个读取excel配置xml文件的方法:
1 // 读取XML配置信息集 2 public ListGetXMLInfo(string xmlpath) 3 { 4 var reader = new XmlTextReader(xmlpath); 5 var doc = new XmlDocument(); 6 doc.Load(reader); 7 8 var headerList = new List (); 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 ///2 /// 模板规则类 3 /// 4 public class Regular 5 { 6 ///7 /// 表头文本 8 /// 9 public string HeaderText { set; get; }10 11 ///12 /// 属性名称13 /// 14 public string PropertyName { set; get; }15 16 ///17 /// 数据类型18 /// 19 public string DataType { set; get; }20 21 private Dictionary_regular = new Dictionary ();22 23 /// 24 /// 表头规则25 /// 26 public DictionaryHeaderRegular27 {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(); 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 ListexcelDTO) 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 ();11 }12 return result;13 }
注:
1.第6行初始化excel导入服务(初始化基本配置信息)
2.第7行验证excel数据,失败则返回具体错误信息
3.验证通过则读取excel数据到DTO
这儿的excelImportService就涉及到整个excel解析工具了,我们先看看整个excel解析的接口与实现文件:
其中Regular前面已经讲过了,是规则集。UploadExcelFileResult则是解析返回结果,内含成功与否,总Message,文件信息,具体错误信息等数据:
////// EXCEL文件上传检查返回数据 /// public class UploadExcelFileResult { ////// 是否成功 /// public bool Success { get; set; } ////// 附带消息 /// public string Message { get; set; } ////// 文件基本信息 /// public FileMessage FileMessage { get; set; } ////// 解析失败后错误位置定位信息 /// public ListExcelFileErrorPositions { get; set; } } public class FileMessage { /// /// 上传文件名称 /// public string FileName { get; set; } ////// 文件大小 /// public int Length { get; set; } ////// 文件类型 /// public string Type { get; set; } } public class ExcelFileErrorPosition { ////// 错误行 /// public int RowIndex { get; set; } ////// 错误列集 /// public List CellIndex { get; set; } ////// 错误列具体错误信息 /// public ListErrorMessage { get; set; } /// /// 错误行数据 /// public ListRowContent { get; set; } }
然后我们来看具体的三个接口:
1.IExcelParseBaseService接口是最基础服务接口,里面包含所有需要用到的抽象方法:
1 ///2 /// EXCEL解析基本服务接口 3 /// 4 public interface IExcelParseBaseService 5 { 6 ///7 /// 检查单元格数据类型 8 /// 9 /// 类型10 /// 单元格值11 ///类型是否出错 12 bool CheckDataType(string cellType, string cellValue);13 14 ///15 /// 检查单元格数据是否为空16 /// 17 /// 单元格值18 /// 行空值计数器19 ///数据是否为空 20 bool CheckNull(string cellValue, ref int nullcount);21 22 ///23 /// 去除数据空格24 /// 25 /// 单元格值26 void ReplaceSpace(ref string cellValue);27 28 ///29 /// 判断当前单元格是否为合并单元格30 /// 31 /// 单元格所在列序号32 /// 单元格所在行序号33 /// EXCEL工作表34 ///合并单元格为true 35 bool IsMergedRegionCell(int cellIndex, int rowIndex, ISheet sheet, ref int firstRegionRow);36 37 ///38 /// 读取EXCEL XML配置信息集39 /// 40 /// xml文件路径41 ///42 List GetXMLInfo(string xmlpath);43 }
它的实现类是抽象类ExcelParseBaseService
2.IExcelAnalyzeService接口是excel解析的核心服务,实现对excel的操作
1 ///2 /// EXCEL 解析基础服务 3 /// 4 public interface IExcelAnalyzeService 5 { 6 ///7 /// 获取指定excel文件版本 8 /// 9 /// EXCEL文件名称10 ///11 int GetExcelEdition(string fileName);12 13 /// 14 /// 根据EXCEL版本创建WorkBook15 /// 16 /// EXCEL版本17 /// EXCEL文件18 ///excel文件对应workbook 19 IWorkbook CreateWorkBook(int edition, Stream excelFileStream);20 21 ///22 /// 解析并检查EXCEL表头数据23 /// 24 /// 25 /// 26 /// 27 ///28 Dictionary GetExcelHeaders(ISheet sheet, ref UploadExcelFileResult uploadExcelFileResult,29 List list);30 31 /// 32 /// 读取EXCEL数据33 /// 34 ///数据对象 35 /// 工作簿对应工作表36 /// excel工作表名称37 /// 该excel规则集38 /// 表头字典39 /// 总数据行数40 ///解析后的Excel数据集 41 ListGetExcelDatas (ISheet sheet, string sheetName, List list,42 Dictionary dict, int rowCount);43 44 /// 45 /// 检查excel数据46 /// 47 /// excel工作表48 /// 规则集49 /// 表头50 /// 总数据行数51 ///检查结果 52 UploadExcelFileResult CheckExcelDatasEnableNull(ISheet sheet, Listlist, Dictionary dict,int rowCount);53 }
它的实现类是ExcelAnalyzeService,也是抽象类并继承于Base服务ExcelParseBaseService
3.IExcelImportService接口就是对外暴漏的excel解析工具类的接口,只含两个方法:验证和读取;
1 ///2 /// Excel 导入基础服务接口 3 /// 4 public interface IExcelImportService 5 { 6 ///7 /// 综合验证Excel表格符合性 8 /// 9 ///10 UploadExcelFileResult ValidateExcel();11 12 /// 13 /// 导入EXCEL文件14 /// 15 ///数据对象DTO 16 ///EXCEL数据集合 17 ListImport ();18 }
它的实现是ExcelImportService,继承于抽象类ExcelAnalyzeService。是我们外部调用excel工具的入口
具体各个类方法的实现,下一篇文章再继续贴代码。
本篇文章主要讲述了通过配置xml文件解析多模板excel表格数据的设计流程与主要框架,附带部分规则代码。具体工具内接口方法实现,请关注下一篇文章。
原创文章,代码都是从自己项目里贴出来的。转载请注明出处哦,亲~~~