最近比较闲,随手写了个类来生成Excel文件,写完用的时候发现几个问题。找不到人帮忙,所以发出来请大家指点指点。
先贴代码吧!
Excel生成
用的时候需要在T的实体类上添加特性后调用
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Reflection;
namespace AFS.Service.Common
{
/// <summary>
/// Excel字段特性
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ExcelColumnAttribute : Attribute
{
public ExcelColumnAttribute(String colhead, int colindex)
{
this.ColumnHeader = colhead;
this.ColumnIndex = colindex;
}
/// <summary>
/// 列名称
/// </summary>
public String ColumnHeader
{
get;
set;
}
/// <summary>
///
/// </summary>
public int ColumnIndex
{
get;
set;
}
}
/// <summary>
/// Excel工具类
/// </summary>
public class ExcelUtility
{
/// <summary>
/// 生成Excel文件
/// </summary>
/// <param name="list"></param>
public void CreateExcelFile<T>(IList<T> list)
{
#region 文件头
//Response.Clear();
HttpContext.Current.Response.Buffer = true;
HttpContext.Current.Response.Charset = "GB2312";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("GB2312");
HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=Report.xls");
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
StringBuilder htmlBuilder = new StringBuilder();
htmlBuilder.AppendLine(
"<html><head><meta http-equiv=Content-Type content=\"text/html; charset=GB2312\"></head><body>")
.AppendLine("<table width='100%' id='jigou' cellspacing='0' rules='all' bgcolor='#FFFFFF' border='1' style='border-color:#95BCDD;100%;border-collapse:collapse;'>")
.AppendLine("\t<tr align='center' style='background-color:#EDF6FF;height:30px;'>")
.AppendLine("{0}")
.Append("</tr>");
#endregion
//列头控制
Boolean columnHeader = true;
//列头内容
StringBuilder columnHeaderStr = new StringBuilder();
if (list.Count < 1)
{
//无数据时只添加表头
PropertyInfo[] plist = typeof(T).GetProperties();
//对所有属性进行排序
OrderPropertys(ref plist);
foreach (PropertyInfo p in plist)
{
Object[] a = p.GetCustomAttributes(typeof(ExcelColumnAttribute), true);
if (a.Length > 0)
{
ExcelColumnAttribute d = ((ExcelColumnAttribute)a[0]);
//填充列头
columnHeaderStr.AppendFormat("<td>{0}</td>", d.ColumnHeader);
}
}
}
else
{
foreach (T t in list)
{
Type ut = t.GetType();
PropertyInfo[] plist = ut.GetProperties();
//对所有属性进行排序
OrderPropertys(ref plist);
htmlBuilder.AppendLine("<tr>");
foreach (PropertyInfo p in plist)
{
Object[] a = p.GetCustomAttributes(typeof(ExcelColumnAttribute), true);
if (a.Length > 0)
{
ExcelColumnAttribute d = ((ExcelColumnAttribute)a[0]);
//填充列头
if (columnHeader)
{
columnHeaderStr.AppendFormat("<td>{0}</td>", d.ColumnHeader);
}
Object value = ut.GetProperty(p.Name).GetValue(t, null);
//填充列数据
htmlBuilder.AppendFormat("<td>{0}</td>", (value == null ? "" : value.ToString()));
}
}
//列头控制
if (columnHeader)
{
columnHeader = false;
}
htmlBuilder.AppendLine("</tr>");
}
}
htmlBuilder.Append("</table></body></html>");
HttpContext.Current.Response.Write(String.Format(htmlBuilder.ToString(), columnHeaderStr));
HttpContext.Current.Response.End();
}
/// <summary>
/// 对所有属性进行排序
/// </summary>
/// <param name="plist"></param>
private void OrderPropertys(ref PropertyInfo[] plist)
{
//对所有属性排序
for (int i = 0; i < plist.Length; i++)
{
Object[] pi = plist[i].GetCustomAttributes(typeof(ExcelColumnAttribute), true);
for (int j = 0; j < plist.Length; j++)
{
Object[] pj = plist[j].GetCustomAttributes(typeof(ExcelColumnAttribute), true);
if (pi.Length > 0 && pj.Length > 0)
{
if (((ExcelColumnAttribute)pi[0]).ColumnIndex > ((ExcelColumnAttribute)pj[0]).ColumnIndex)
{
Object temp = plist[i];
plist[i] = plist[j];
plist[j] = (PropertyInfo)temp;
}
}
}
}
}
}
}
实体
现在有两个问题,首先是CreateExcelFile这个方法,感觉太长了点,没啥好的方案来优化。这个倒是也无所谓。
public class Entity
{
[ExcelColumn("编号",1)]
public int Id{set;get;}
[ExcelColumn("名称",1)]
public String Name{set;get;}
}
public static void Main()
{
IList<Entity> list = GetData();
ExcelUtility excelUtility = new ExcelUtility();
excelUtility.CreateExcelFile<Entity>(list);
}
关键问题是,这样的生成方式很不方便对数据做额外的处理,很多实体类都是根据数据表来生成的,比如可能实体类中性别存的是1,2,我先 导出Excel要变成男,女;类似这样的情况,这个类就没办法处理。除非在实体类上做手脚,但是那样感觉背离了把生成Excel操作封装起来的原意,因为可能非Excel不需要变成男,女。
大家有什么想法没?小弟这里拜谢了。