上一篇文章介绍了一些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文件具体怎么配置:

 <?xml version="1.0" encoding="utf-8" ?>
<module>
<add firstHeaderRow="" lastHeaderRow="" sheetCount=""/>
<add headerText="姓名" propertyName="Name" dataType="System.String"/>
<add headerText="手机号码" propertyName="PhoneNumber" dataType="System.String"/>
<add headerText="性别" propertyName="Sex" dataType="System.Boolean"/>
<add headerText="民族" propertyName="Nation" dataType="System.String"/>
<add headerText="出生日期" propertyName="Birthday" dataType="System.String"/>
<add headerText="身份证号码" propertyName="Cardid" dataType="System.String"/>
</module>

再写一个读取excel配置xml文件的方法:

         // 读取XML配置信息集
public List<Regular> GetXMLInfo(string xmlpath)
{
var reader = new XmlTextReader(xmlpath);
var doc = new XmlDocument();
doc.Load(reader); var headerList = new List<Regular>();
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
var header = new Regular(); if (node.Attributes["firstHeaderRow"] != null)
header.HeaderRegular.Add("firstHeaderRow", int.Parse(node.Attributes["firstHeaderRow"].Value));
if (node.Attributes["lastHeaderRow"] != null)
header.HeaderRegular.Add("lastHeaderRow", int.Parse(node.Attributes["lastHeaderRow"].Value));
if (node.Attributes["sheetCount"] != null)
header.HeaderRegular.Add("sheetCount", int.Parse(node.Attributes["sheetCount"].Value)); if (node.Attributes["headerText"] != null)
header.HeaderText = node.Attributes["headerText"].Value;
if (node.Attributes["propertyName"] != null)
header.PropertyName = node.Attributes["propertyName"].Value;
if (node.Attributes["dataType"] != null)
header.DataType = node.Attributes["dataType"].Value; headerList.Add(header);
}
return headerList;
}

其中涉及到一个我们自己创建的规则类,Regular

     /// <summary>
/// 模板规则类
/// </summary>
public class Regular
{
/// <summary>
/// 表头文本
/// </summary>
public string HeaderText { set; get; } /// <summary>
/// 属性名称
/// </summary>
public string PropertyName { set; get; } /// <summary>
/// 数据类型
/// </summary>
public string DataType { set; get; } private Dictionary<string, int> _regular = new Dictionary<string, int>(); /// <summary>
/// 表头规则
/// </summary>
public Dictionary<string, int> HeaderRegular
{
get { return _regular; }
set { _regular = value; }
}
}

这样,我们就能将一个excel的配置信息读取出来备用。

具体上传文件的接口就不在这儿粘贴了,以前有一篇文章介绍过wenAPI做文件上传,地址:

http://www.cnblogs.com/csqb-511612371/p/4871574.html

我们在文件上传成功后的逻辑是调用服务ImportExcel,解析出excel数据到DTO,然后再将DTO映射到实体入库。

那么就会有这样一段代码:

                             var xmlName = getXml();// 自己定义的获取配置文件名称方法
var excelDataDtos = new List<ExcelDataDTO>();
var result = attachmentFileService.ImportExcel(excelFilePath, xmlName, ref excelDataDtos);
if (result.Success)
{
9 foreach (var excelDataDto in excelDataDtos)
{
// 数据入库
employeeInfoService.HR_Add_EmployeeInfo(excelDataDto);
}
}
ExcelDataDTO是我们对应这个excel文件的DTO,此处简要的直接new了,也应该是单独服务产生(因为我们这个方法是实现多模板上传)。
第3行ImportExcel方法中将执行逻辑:获取基础配置信息->验证excel数据->读取excel数据
        public UploadExcelFileResult ImportExcel(string filePath, string xmlPath, ref List<ExcelDataDTO> excelDTO)
{
// XML配置文件绝对路径
var xmlFilePath = ExcelTemplateBasePath + xmlPath; var excelImportService = new ExcelImportService(filePath, xmlFilePath);
var result = excelImportService.ValidateExcel();
if (result.Success)
{
excelDTO = excelImportService.Import<ExcelDataDTO>();
}
return result;
}

注:

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接口是最基础服务接口,里面包含所有需要用到的抽象方法:

     /// <summary>
/// EXCEL解析基本服务接口
/// </summary>
public interface IExcelParseBaseService
{
/// <summary>
/// 检查单元格数据类型
/// </summary>
/// <param name="cellType">类型</param>
/// <param name="cellValue">单元格值</param>
/// <returns>类型是否出错</returns>
bool CheckDataType(string cellType, string cellValue); /// <summary>
/// 检查单元格数据是否为空
/// </summary>
/// <param name="cellValue">单元格值</param>
/// <param name="nullcount">行空值计数器</param>
/// <returns>数据是否为空</returns>
bool CheckNull(string cellValue, ref int nullcount); /// <summary>
/// 去除数据空格
/// </summary>
/// <param name="cellValue">单元格值</param>
void ReplaceSpace(ref string cellValue); /// <summary>
/// 判断当前单元格是否为合并单元格
/// </summary>
/// <param name="cellIndex">单元格所在列序号</param>
/// <param name="rowIndex">单元格所在行序号</param>
/// <param name="sheet">EXCEL工作表</param>
/// <returns>合并单元格为true</returns>
bool IsMergedRegionCell(int cellIndex, int rowIndex, ISheet sheet, ref int firstRegionRow); /// <summary>
/// 读取EXCEL XML配置信息集
/// </summary>
/// <param name="xmlpath">xml文件路径</param>
/// <returns></returns>
List<Regular> GetXMLInfo(string xmlpath);
}

它的实现类是抽象类ExcelParseBaseService

2.IExcelAnalyzeService接口是excel解析的核心服务,实现对excel的操作

     /// <summary>
/// EXCEL 解析基础服务
/// </summary>
public interface IExcelAnalyzeService
{
/// <summary>
/// 获取指定excel文件版本
/// </summary>
/// <param name="fileName">EXCEL文件名称</param>
/// <returns></returns>
int GetExcelEdition(string fileName); /// <summary>
/// 根据EXCEL版本创建WorkBook
/// </summary>
/// <param name="edition">EXCEL版本</param>
/// <param name="excelFileStream">EXCEL文件</param>
/// <returns>excel文件对应workbook</returns>
IWorkbook CreateWorkBook(int edition, Stream excelFileStream); /// <summary>
/// 解析并检查EXCEL表头数据
/// </summary>
/// <param name="sheet"></param>
/// <param name="uploadExcelFileResult"></param>
/// <param name="list"></param>
/// <returns></returns>
Dictionary<int, string> GetExcelHeaders(ISheet sheet, ref UploadExcelFileResult uploadExcelFileResult,
List<Regular> list); /// <summary>
/// 读取EXCEL数据
/// </summary>
/// <typeparam name="TableDTO">数据对象</typeparam>
/// <param name="sheet">工作簿对应工作表</param>
/// <param name="sheetName">excel工作表名称</param>
/// <param name="list">该excel规则集</param>
/// <param name="dict">表头字典</param>
/// <param name="rowCount">总数据行数</param>
/// <returns>解析后的Excel数据集</returns>
List<TableDTO> GetExcelDatas<TableDTO>(ISheet sheet, string sheetName, List<Regular> list,
Dictionary<int, string> dict, int rowCount); /// <summary>
/// 检查excel数据
/// </summary>
/// <param name="sheet">excel工作表</param>
/// <param name="list">规则集</param>
/// <param name="dict">表头</param>
/// <param name="rowCount">总数据行数</param>
/// <returns>检查结果</returns>
UploadExcelFileResult CheckExcelDatasEnableNull(ISheet sheet, List<Regular> list, Dictionary<int, string> dict,int rowCount);
}

它的实现类是ExcelAnalyzeService,也是抽象类并继承于Base服务ExcelParseBaseService

3.IExcelImportService接口就是对外暴漏的excel解析工具类的接口,只含两个方法:验证和读取;

     /// <summary>
/// Excel 导入基础服务接口
/// </summary>
public interface IExcelImportService
{
/// <summary>
/// 综合验证Excel表格符合性
/// </summary>
/// <returns></returns>
UploadExcelFileResult ValidateExcel(); /// <summary>
/// 导入EXCEL文件
/// </summary>
/// <typeparam name="TableDTO">数据对象DTO</typeparam>
/// <returns>EXCEL数据集合</returns>
List<TableDTO> Import<TableDTO>();
}

它的实现是ExcelImportService,继承于抽象类ExcelAnalyzeService。是我们外部调用excel工具的入口

具体各个类方法的实现,下一篇文章再继续贴代码。

本篇文章主要讲述了通过配置xml文件解析多模板excel表格数据的设计流程与主要框架,附带部分规则代码。具体工具内接口方法实现,请关注下一篇文章。

原创文章,代码都是从自己项目里贴出来的。转载请注明出处哦,亲~~~

NPOI操作EXCEL(二)——大量不同模板时设计方式的更多相关文章

  1. NPOI操作Excel(二)--创建Excel并设置样式

    由于XSSF中的XSSFWorkbook和HSSF中的HSSFWorkbook拥有的属性.方法等都是一样的,故下面就已一个为例做为展示,他们都继承与一个接口:IWorkbook(命名空间:using  ...

  2. 2.6.2 用NPOI操作EXCEL--设置密码才可以修改单元格内容

    2.6.2 用NPOI操作EXCEL--设置密码       有时,我们可能需要某些单元格只读,如在做模板时,模板中的数据是不能随意让别人改的.在Excel中,可以通过“审阅->保护工作表”来完 ...

  3. C#开发中使用Npoi操作excel实例代码

    C#开发中使用Npoi操作excel实例代码 出处:西西整理 作者:西西 日期:2012/11/16 9:35:50 [大 中 小] 评论: 0 | 我要发表看法 Npoi 是什么? 1.整个Exce ...

  4. 使用NPOI操作Excel文件及其日期处理

    工作中经常遇到需要读取或导出Excel文件的情况,而NPOI是目前最宜用.效率最高的操作的Office(不只是Excel哟)文件的组件,使用方便,不详细说明了. Excel工作表约定:整个Excel表 ...

  5. NPOI操作Excel辅助类

    /// <summary> /// NPOI操作excel辅助类 /// </summary> public static class NPOIHelper { #region ...

  6. NPOI操作excel之写入数据到excel表

    在上一篇<NPOI操作excel之读取excel数据>我们把excel数据写入了datatable中,本篇就讲如何把datatable数据写入excel中. using System; u ...

  7. 用NPOI操作EXCEL关于HSSFClientAnchor(dx1,dy1,dx2,dy2,col1,row1,col2,row2)的参数

    2.4.1 用NPOI操作EXCEL关于HSSFClientAnchor(dx1,dy1,dx2,dy2,col1,row1,col2,row2)的参数   NPOI教程:http://www.cnb ...

  8. C# 如何使用NPOI操作Excel以及读取合并单元格等

    C#操作Excel方法有很多,以前用的需要电脑安装office才能用,但因为版权问题公司不允许安装office.所以改用NPOI进行Excel操作,基本上一些简单的Excel操作都没有问题,读写合并单 ...

  9. 用NPOI操作EXCEL-锁定列CreateFreezePane()

    public void ExportPermissionRoleData(string search, int roleStatus) { var workbook = new HSSFWorkboo ...

随机推荐

  1. java继承覆盖与向上转型,权限

    子类可以覆盖父类的非final成员变量和重写非final方法 private私有变量和方法只能在类的内部使用,因此子类继承的同时会被隐藏,相当于不继承 protected变量,子类可以继承调用 方法被 ...

  2. ASP.NET Core 中文文档 第四章 MVC(2.2)模型验证

    原文:Model Validation 作者:Rachel Appel 翻译:娄宇(Lyrics) 校对:孟帅洋(书缘) 在这篇文章中: 章节: 介绍模型验证 验证 Attribute 模型状态 处理 ...

  3. 基于Metronic的Bootstrap开发框架经验总结(13)--页面链接收藏夹功能的实现2(利用Sortable进行拖动排序)

    在上篇随笔<基于Metronic的Bootstrap开发框架经验总结(12)--页面链接收藏夹功能的实现>上,我介绍了链接收藏夹功能的实现,以及对收藏记录的排序处理.该篇随笔主要使用功能按 ...

  4. 【无私分享:ASP.NET CORE 项目实战(第十一章)】Asp.net Core 缓存 MemoryCache 和 Redis

    目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 经过 N 久反复的尝试,翻阅了网上无数的资料,GitHub上下载了十几个源码参考, Memory 和 Redis 终于写出一个 ...

  5. PHP flush()与ob_flush()的区别

    buffer ---- flush()buffer是一个内存地址空间,Linux系统默认大小一般为4096(1kb),即一个内存页.主要用于存储速度不同步的设备或者优先级不同的 设备之间传办理数据的区 ...

  6. node使用xml-writer生成本地XML文件实例

    npm中xml-writer文档的链接地址:https://www.npmjs.com/package/xml-writer npm中的文档比较简单,而且生成本地xml文件的demo并不正确.本篇是对 ...

  7. Drupal 8.2.4安装简体中文步骤

    安装的时候发现很多情况下会出现各种问题,现在写下自己安装成功的步骤: 1.首先官网下载zip安装包drupal-8.2.4.zip 2.下载官方提供的8.2.4简体中文语言包drupal-8.2.4. ...

  8. JQuery中$.ajax()方法参数详解

    url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. type: 要求为String类型的参数,请求方式(post或get)默认为get.注意其他http请求方法,例如put和 ...

  9. 提示用户升级浏览器代码 低于ie9的浏览器提示

    一般想做一些酷炫的网站都有个烦恼,那就是兼容ie浏览器,好在现在使用ie的也越来越少,微软也转战edge浏览器. 使用 Bootstrap经常用js插件可以模拟兼容旧版本的浏览器(bsie 鄙视IE) ...

  10. AlloyTouch全屏滚动插件发布--30秒搞定顺滑H5页

    原文链接:https://github.com/AlloyTeam/AlloyTouch/wiki/AlloyTouch-FullPage-Plugin 先验货 插件代码可以在这里找到. 注意,虽然是 ...