NPOI操做EXCEL(二)——大量不一樣模板時設計方式

上一篇文章介紹了一些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表格數據的設計流程與主要框架,附帶部分規則代碼。具體工具內接口方法實現,請關注下一篇文章。

 

原創文章,代碼都是從本身項目裏貼出來的。轉載請註明出處哦,親~~~

相關文章
相關標籤/搜索