asp.net开发企业级程序,经常要用到Excel导入导出功能,NPOI提供了比较好的解决方案,但是因为各数据库表的字段不同,而且导入导出的数据列名需要中文命名(数据表字段一般以英文命名),所以需要做一个比较通用的方法,减少日后的工作量。
由于开发中用到三层架构,数据表在程序中用model实体类去表示,所以想到用泛型反射去实现,使用XML去映射数据库表字段与Excel列标题的关系。
比如model的类如下
/// author 柏柏 2013-05-16
public class CNS_CensusMember : ModuleBase
{
public int ID { set; get; }
/// <summary>
/// 户号
/// </summary>
public string RegisterNO { set; get; }
/// <summary>
/// 姓名
/// </summary>
public string Name { set; get; }
/// <summary>
/// 联系电话
/// </summary>
public string Tel { set; get; }
/// <summary>
/// 与户主关系
/// </summary>
public string Relation { set; get; }
/// <summary>
/// 曾用名
/// </summary>
public string OtherName { set; get; }
/// <summary>
/// 性别
/// </summary>
public System.Nullable<short> Sex { set; get; }
/// <summary>
/// 出生地
/// </summary>
public string PlaceOfBirth { set; get; }
/// <summary>
/// 民族
/// </summary>
public string Nationalilty { set; get; }
/// <summary>
/// 祖籍
/// </summary>
public string PlaceOfAncestral { set; get; }
/// <summary>
/// 出生日期
/// </summary>
public System.Nullable<System.DateTime> Brithday { set; get; }
/// <summary>
/// 住址
/// </summary>
public string Address { set; get; }
/// <summary>
/// 宗教信养
/// </summary>
public string Religion { set; get; }
/// <summary>
/// 身份证号
/// </summary>
public string IDCard { set; get; }
/// <summary>
/// 身高
/// </summary>
public string Height { set; get; }
/// <summary>
/// 血型
/// </summary>
public string TypeOfBlood { set; get; }
/// <summary>
/// 文化程度
/// </summary>
public System.Nullable<int> EducationID { set; get; }
/// <summary>
/// 婚姻状况
/// </summary>
public string Marriage { set; get; }
/// <summary>
/// 兵役状况
/// </summary>
public string MilitaryService { set; get; }
/// <summary>
/// 服务处所
/// </summary>
public string Company { set; get; }
/// <summary>
/// 职业
/// </summary>
public string Occupation { set; get; }
/// <summary>
/// 政治面目
/// </summary>
public System.Nullable<int> PoliticalID { set; get; }
/// <summary>
/// 迁入日期
/// </summary>
public System.Nullable<System.DateTime> IngoingDate { set; get; }
/// <summary>
/// 原住地
/// </summary>
public string PreviousAddress { set; get; }
/// <summary>
/// 迁入原因
/// </summary>
public string IngoingReason { set; get; }
/// <summary>
/// 迁出日期
/// </summary>
public System.Nullable<System.DateTime> MoveOutDate { set; get; }
/// <summary>
/// 迁出到
/// </summary>
public string MoveToAddress { set; get; }
/// <summary>
/// 是否注销
/// </summary>
public System.Nullable<bool> IsCanceled { set; get; }
/// <summary>
/// 注销日期
/// </summary>
public System.Nullable<System.DateTime> CancelDate { set; get; }
/// <summary>
/// 注销原因
/// </summary>
public string CancelReason { set; get; }
/// <summary>
/// 备注
/// </summary>
public string Remark { set; get; }
/// <summary>
/// 文化水平
/// </summary>
public string Education { set; get; }
/// <summary>
/// 户别
/// </summary>
public string CensusTypeName { set; get; }
/// <summary>
/// 政治面目
/// </summary>
public string Political { set; get; }
/// <summary>
/// 性别
/// </summary>
public string SexName { set; get; }
/// <summary>
/// 户主
/// </summary>
public string HouseHolder { set; get; }
}
再写一个xml文件作为与Excel的映射,如下。headerText对应excel的列标题,propertyName对于数据库数据字段名,也就是model的属性名。
<?xml version="1.0" encoding="utf-8" ?>
<module>
<add headerText="户别" propertyName="CensusTypeName" dataType="System.String" width="100" />
<add headerText="户号" propertyName="RegisterNO" dataType="System.String" width="100" />
<add headerText="户主" propertyName="HouseHolder" dataType="System.String" width="100" />
<add headerText="姓名" propertyName="Name" dataType="System.String" width="100" />
<add headerText="与户主关系" propertyName="Relation" dataType="System.String" width="100" />
<add headerText="曾用名" propertyName="OtherName" dataType="System.String" width="100" />
<add headerText="姓别" propertyName="SexName" dataType="System.String" width="100"/>
<add headerText="出生地" propertyName="PlaceOfBirth" dataType="System.String" width="100" />
<add headerText="民族" propertyName="Nationalilty" dataType="System.String" width="100" />
<add headerText="籍贯" propertyName="PlaceOfAncestral" dataType="System.String" width="100" />
<add headerText="出生日期" propertyName="Brithday" dataType="System.DateTime" width="100" />
<add headerText="其他地址" propertyName="Address" dataType="System.String" width="100" />
<add headerText="宗教信养" propertyName="Religion" dataType="System.String" width="100" />
<add headerText="身份证号" propertyName="IDCard" dataType="System.String" width="100" />
<add headerText="身高" propertyName="Height" dataType="System.String" width="100" />
<add headerText="血型" propertyName="TypeOfBlood" dataType="System.String" width="100" />
<add headerText="婚姻状况" propertyName="Marriage" dataType="System.String" width="100" />
<add headerText="兵役状况" propertyName="MilitaryService" dataType="System.String" width="100" />
<add headerText="服务处所" propertyName="Company" dataType="System.String" width="100" />
<add headerText="迁入日期" propertyName="IngoingDate" dataType="System.DateTime" width="100" />
<add headerText="政治面目" propertyName="Political" dataType="System.String" width="100" />
<add headerText="已注销" propertyName="IsCanceled" dataType="System.Boolean" width="100" />
</module>
再写实体类对应XML文件,以便对xml的读取和对excel列头的操作,如下
/// author 柏柏 2013-05-16
public class ExcelHeader
{
private Dictionary<string, string> _Mapping = new Dictionary<string, string>();
/// <summary>
/// 映射值的转换
/// </summary>
public Dictionary<string, string> Mapping
{
get { return _Mapping; }
set { _Mapping = value; }
}
public string MappingTo { set; get; }
public int Width { set; get; }
public string HeaderText { set; get; }
public string PropertyName { set; get; }
public string DataType { set; get; }
public ExcelHeader()
{
}
public ExcelHeader(string headerText, string propertyName, int width)
{
this.HeaderText = headerText;
this.Width = width;
this.PropertyName = propertyName;
}
}
读取xml的类如下
/// <summary>
/// author 柏柏 2013-05-16
/// </summary>
public class WebExcelHelper
{
public List<ExcelHeader> GetExcelHeader(string template)//template为xml的路径名称
{
XmlTextReader reader = new XmlTextReader(System.Web.HttpContext.Current.Server.MapPath(template));
XmlDocument doc = new XmlDocument();
doc.Load(reader);
string format = "^[0-9]*$";
Regex regex = new Regex(format);
List<ExcelHeader> headerList = new List<ExcelHeader>();
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
ExcelHeader header = new ExcelHeader();
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;
if (node.Attributes["to"] != null)
header.MappingTo = node.Attributes["to"].Value;
if (node.Attributes["width"] != null)
{
string width = node.Attributes["width"].Value;
if (regex.IsMatch(width))
{
header.Width = int.Parse(node.Attributes["width"].Value);
}
}
foreach (XmlNode subNode in node.ChildNodes)
{
header.Mapping.Add(subNode.Attributes["text"].Value, subNode.Attributes["value"].Value);
}
headerList.Add(header);
}
return headerList;
}
}
再来看看NPOI导入导出的方法,这个类是参考网上的方法,只是把用DataTable的实现改为泛型的实现
public class ExcelHelper
{
/// <summary>
/// 作者
/// </summary>
public string Author { set; get; }
/// <summary>
/// 应用程序名
/// </summary>
public string ApplicationName { set; get; }
/// <summary>
/// 介绍、简介
/// </summary>
public string Comments { set; get; }
/// <summary>
/// NPOI简单Demo,快速入门代码
/// </summary>
/// <param name="dtSource"></param>
/// <param name="strFileName"></param>
/// <remarks>NPOI认为Excel的第一个单元格是:(0,0)</remarks>
public void ExportEasy(DataTable dtSource, string strFileName)
{
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.CreateSheet();
//填充表头
HSSFRow dataRow = sheet.CreateRow(0);
foreach (DataColumn column in dtSource.Columns)
{
dataRow.CreateCell(column.Ordinal).SetCellValue(column.ColumnName);
}
//填充内容
for (int i = 0; i < dtSource.Rows.Count; i++)
{
dataRow = sheet.CreateRow(i + 1);
for (int j = 0; j < dtSource.Columns.Count; j++)
{
dataRow.CreateCell(j).SetCellValue(dtSource.Rows[i][j].ToString());
}
}
//保存
using (MemoryStream ms = new MemoryStream())
{
using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
{
workbook.Write(ms);
ms.Flush();
ms.Position = 0;
byte[] data = ms.ToArray();
fs.Write(data, 0, data.Length);
fs.Flush();
}
}
sheet.Dispose();
workbook.Dispose();
}
/// <summary>
/// ListToExcel
/// </summary>
/// <param name="list">数据源</param>
/// <param name="strFileName">文件保存路径</param>
/// <param name="nameList">列头信息</param>
public void ListToExcel<T>(List<T> list, string strHeaderText, string strFileName, List<ExcelHeader> hearderList)
{
//保存
using (MemoryStream ms = this.Export<T>(list, strHeaderText, hearderList))
{
using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write))
{
ms.Flush();
ms.Position = 0;
byte[] data = ms.ToArray();
fs.Write(data, 0, data.Length);
fs.Flush();
}
}
}
private short GetXLColour(HSSFWorkbook workbook, System.Drawing.Color SystemColour)
{
short s = 0;
HSSFPalette XlPalette = workbook.GetCustomPalette();
HSSFColor XlColour = XlPalette.FindColor(SystemColour.R, SystemColour.G, SystemColour.B);
if (XlColour == null)
{
if (NPOI.HSSF.Record.PaletteRecord.STANDARD_PALETTE_SIZE < 255)
{
if (NPOI.HSSF.Record.PaletteRecord.STANDARD_PALETTE_SIZE < 64)
{
NPOI.HSSF.Record.PaletteRecord.STANDARD_PALETTE_SIZE = 64; NPOI.HSSF.Record.PaletteRecord.STANDARD_PALETTE_SIZE += 1;
XlColour = XlPalette.AddColor(SystemColour.R, SystemColour.G, SystemColour.B);
}
else { XlColour = XlPalette.FindSimilarColor(SystemColour.R, SystemColour.G, SystemColour.B); }
s = XlColour.GetIndex();
}
}
else
s = XlColour.GetIndex();
return s;
}
/// <summary>
/// 从excel导入数据到数组
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="ExcelFileStream"></param>
/// <param name="SheetIndex"></param>
/// <param name="HeaderRowIndex"></param>
/// <returns></returns>
public List<T> Import<T>(Stream ExcelFileStream, int SheetIndex, int HeaderRowIndex, List<ExcelHeader> list)
{
HSSFWorkbook workbook = new HSSFWorkbook(ExcelFileStream);
HSSFSheet sheet = workbook.GetSheetAt(SheetIndex);
List<T> resultList = new List<T>();
HSSFRow headerRow = sheet.GetRow(HeaderRowIndex);
int cellCount = headerRow.LastCellNum;
Dictionary<int, string> dict = new Dictionary<int, string>();
for (int i = headerRow.FirstCellNum; i < cellCount; i++)
{
dict.Add(i, headerRow.GetCell(i).StringCellValue);
}
int rowCount = sheet.LastRowNum;
T model = default(T);
for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
{
HSSFRow row = sheet.GetRow(i);
model = Activator.CreateInstance<T>();//产生一个新的泛型对象
for (int j = row.FirstCellNum; j < cellCount; j++)
{
ExcelHeader header = list.Find(f => f.HeaderText == dict[j]);
string property = header.PropertyName;
string value = row.GetCell(j).ToString();
if (header.Mapping.Count > 0)
{
value = header.Mapping[value];
property = header.MappingTo;
}
PropertyInfo prop = model.GetType().GetProperty(property);
try
{
if (prop == null)
continue;
switch (header.DataType)
{
case "System.Decimal":
if (Regexlib.MatchDecimal(value))
prop.SetValue(model, Convert.ToDecimal(value), null);
break;
case "System.Int16":
if (Regexlib.MatchInt(value))
prop.SetValue(model, Convert.ToInt16(value), null);
break;
case "System.Int32":
if (Regexlib.MatchInt(value))
prop.SetValue(model, Convert.ToInt32(value), null);
break;
case "System.Boolean":
if(value!=null&&value.Length>0)
prop.SetValue(model, Convert.ToBoolean(value), null);
break;
case "System.DateTime":
if (Regexlib.MatchDate(value))
prop.SetValue(model, Convert.ToDateTime(value), null);
break;
default:
prop.SetValue(model, value, null);
break;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
resultList.Add(model);
}
ExcelFileStream.Close();
workbook = null;
sheet = null;
return resultList;
}
}
最后就是使用方法,使用时只需修改一个泛型model的对象和XML的路径就可以了,当然需要做一个相应的XML文件,如下在于XML可以在程序外部修改。当然需要更改导入导出的字段时只需要修改XML文件就可以了。
导出方法
protected void btnLoadOut_Click(object sender, EventArgs e)
{
List<FineOffice.Modules.CNS_CensusMember> list = memberBll.GetListALL();
FineOffice.Web.WebExcelHelper excelHelper = new FineOffice.Web.WebExcelHelper();
List<FineOffice.Common.FileHelper.ExcelHeader> headerList = excelHelper.GetExcelHeader("~/Config/Template/CensusMember.xml");//XML路径名
FineOffice.Common.FileHelper.ExcelHelper toExcel = new FineOffice.Common.FileHelper.ExcelHelper();
System.IO.MemoryStream ms = toExcel.Export<FineOffice.Modules.CNS_CensusMember>(list, gridMember.Title, headerList);导出
byte[] output = ms.ToArray();
FineOffice.Web.FileTypeHelper typeHelper = new FineOffice.Web.FileTypeHelper();
Response.AddHeader("Content-Disposition", "attachment; filename=" + typeHelper.ToHexString(string.Format("{0}{1:yyyyMMdd}", gridMember.Title, DateTime.Now) + ".xls"));
Response.AddHeader("Content-Length", output.Length.ToString());
Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");//设置输出流的字符集
Response.OutputStream.Write(output, 0, output.Length); //输出
Response.Flush();
Response.End();
}
导入方法
protected void btnLoadIn_Click(object sender, EventArgs e)
{
try
{
if (uploadFile.HasFile)
{
HttpPostedFile excel=uploadFile.PostedFile;
Stream fileStream = excel.InputStream;
FineOffice.Web.WebExcelHelper excelHelper = new FineOffice.Web.WebExcelHelper();
System.Collections.Generic.List<FineOffice.Common.FileHelper.ExcelHeader> headerList = excelHelper.GetExcelHeader("~/Config/Template/CensusMember.xml");
FineOffice.Common.FileHelper.ExcelHelper toExcel = new FineOffice.Common.FileHelper.ExcelHelper();
List<FineOffice.Modules.CNS_CensusMember> list= toExcel.Import<FineOffice.Modules.CNS_CensusMember>(fileStream, 0, 0, headerList);
fileStream.Close();
uploadFile.Reset();
gridMember.DataSource = list;
gridMember.DataBind();
}
}
catch (Exception ex)
{
Alert.Show(ex.Message);
}
}
至此就完成了
欢迎转载,转载请注明出处,博客园:http://www.cnblogs.com/feng84/archive/2013/05/18/3085010.html