上一篇文章介绍了一些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. ldap部署相关,ldap双机\LAM配置管理\ldap备份还原

    前言 接之前我的文章,django+ldap+memcache实现单点登录+统一认证 就单点登录实现过程进行详细记录,ldap是一切的基础,可以把它理解成一个读强写弱的文件类型数据库,统一认证我们通过 ...

  2. LinqToDB 源码分析——DataContext类

    LinqToDB框架是一个轻量级的ORM框架.当然,功能上来讲一定比不上Entity Framework的强大.但是在使用上总让笔者感觉有一点Entity Framework的影子.笔者想过可能的原因 ...

  3. 关于c#在DataTable中根据条件删除某一行

    我们经常会将数据源放在DataTable里面,但是有时候也需要移除不想要的行,下面的代码告诉你们 DataTable dts:                DataRow[] foundRow;   ...

  4. c++ builder 2010 错误 F1004 Internal compiler error at 0x9740d99 with base 0x9

    今天遇到一个奇怪的问题,拷贝项目后,在修改,会出现F1004 Internal compiler error at 0x9740d99 with base 0x9 ,不管怎么改,删除改动,都没用,关闭 ...

  5. 【转】zigbee终端无法重连的问题解决

    zigbee终端无法重连的问题解决 1.zigbee重连的原因 (1)zigbee由于各种原因的干扰导致信号太差而掉线. (2)协调器重启. 2.zigbee终端重连的处理 (1)zigbee掉线后会 ...

  6. hibernate 中根据id删除一条记录的语句

    qid name like content 1 A 1 the first text 2 B 2 the Second text 1 C 3 the Third text 如上表所示,当我们需要某个q ...

  7. java访问修饰符

    了解面向对象思想的同学们,都知道"封装"这一基本特征,如何正确运用访问修饰符,恰恰能体现出封装的好坏. java访问修饰符有四个: 1)public:访问权限最高,其修饰的类.类变 ...

  8. Java接口响应超时监控

    为什么要监控 服务化接口是提供服务的,接口正确性.稳定性是最最重要的,在保证正确的同时需要尽量提高接口响应时间. 有的团队会有专门的工具来对系统响应时间.吞吐量做监控,但如果团队没有这种"待 ...

  9. Linux Cmd Tool 系列之—alias

    The alias cmd list your current aliases. For example : alias Use alias to shorten a long cmd in curr ...

  10. Xshell显示中文乱码问题

    [文件]–>[打开]–>在打开的session中选择连接的那个,点击[属性] -> [终端], 编码选择为:Unicode(UTF-8),然后重新连接服务器即可.也可以在Xshell ...