NPOI导入,导出

概述

NPOI 是 POI 项目的 .NET 版本。POI是一个开源的Java读写Excel、WORD等微软OLE2组件文档的项目。NPOI 可以在没有安装 Office 或者相应环境的机器上对 WORD/EXCEL 文档进行读写,包含了大部分EXCEL的特性(单元格样式、数据格式、公式等等)。(复制百度百科)

 

表格导入导出的操作经常会碰到,最近抽空专门封装了一下。

遵循的原则:

1. 一行数据对应一个数据实体,需提供它们二者间的映射关系。

2. 支持合并单元格的导入导出(导出数据只支持竖向合并,导入数据遇到横向合并的单元格会抛出异常),图片未支持

 

导出的复杂在于样式的控制,当解决这一问题后后续操作就很简单了,而样式解析相关的代码行数也真的是不少,因为对API的不熟悉,连写带测折腾了不少时间。

导入因为行为的多变性,要求程序员调用时将具体的读写逻辑以策略的形式传入。所以代码量相对来说要少得多。其实也是避开了一些难题,比如公式符号,数字的上标,下标的解析(尚不知道怎么解决)。

导出效果

 

表格导入

单元格数据的解析

1. 先依据单元格类的数据类型cell.CellType(枚举类型),读取其内部保存的数据,如果类型是公式的,则依据cell.CachedFormulaResultType再进行一次判别。

2. 从单元格读到数据后还再进一步完成一次类型的转换,将它转换为我们需要的类型。

/// <summary>
/// 扩展
/// </summary>
public static class IRowExtension
{
    /// <summary>
    /// 读取表格中某单元格的值,如果单元格是合并单元格,则竖向合并的正常返回,横向合并的抛出异常
    /// </summary>
    /// <typeparam name="A">要读取的数据类型</typeparam>
    /// <param name="row">Excel中的某行数据</param>
    /// <param name="index">行内的列下标</param>
    /// <returns></returns>
    public static A GetValue<A>(this IRow row, int index)
    {
        try
        {
            //获取单元格
            ICell cell = row.GetCell(index);

            //判别是否合并单元格
            if (cell.IsMergedCell)
            {
                ISheet sheet = cell.Sheet;
                for (int i = 0, length = sheet.NumMergedRegions; i < length; i++)
                {
                    var cellRange = sheet.GetMergedRegion(i);
                    if (cell.ColumnIndex >= cellRange.FirstColumn
                        && cell.ColumnIndex <= cellRange.LastColumn
                        && cell.RowIndex >= cellRange.FirstRow
                        && cell.RowIndex <= cellRange.LastRow)
                    {
                        if (cellRange.FirstColumn != cellRange.LastColumn)
                        {
                            throw new Exception("不能有横向合并的单元格");
                        }

                        cell = sheet.GetRow(cellRange.FirstRow).GetCell(cellRange.FirstColumn);
                    }
                }
            }
            return GetValue<A>(cell);
        }
        catch (Exception ex)
        {
            //读取单元格信息时出错
            throw new Exception("出错位置的列下标:" + index + ",报错信息:" + ex.Message);
        }
    }

    /// <summary>
    /// 读取表格中某单元格的值,如果单元格是合并单元格,则竖向合并的正常返回,横向合并的抛出异常
    /// </summary>
    /// <typeparam name="A">要读取的数据类型</typeparam>
    /// <param name="cell">Excel中的某单元格</param>
    /// <returns></returns>
    private static A GetValue<A>(ICell cell)
    {
        //依据单元格数据类型读取数据,并强转为目标类型
        switch (cell.CellType)
        {
            case CellType.Boolean:
                return cell.BooleanCellValue.ChangeType<A>();
            case CellType.Error:
                return ErrorEval.GetText(cell.ErrorCellValue).ChangeType<A>();
            case CellType.Numeric:
                if (DateUtil.IsCellDateFormatted(cell))
                {
                    return cell.DateCellValue.ChangeType<A>();
                }
                else
                {
                    return cell.NumericCellValue.ChangeType<A>();
                }
            case CellType.String:
                string strValue = cell.StringCellValue;
                if (string.IsNullOrEmpty(strValue))
                {
                    return default(A);
                }
                else
                {
                    return strValue.ChangeType<A>();
                }
            case CellType.Formula://公式
                switch (cell.CachedFormulaResultType)
                {
                    case CellType.Boolean:
                        return cell.BooleanCellValue.ChangeType<A>();
                    case CellType.Error:
                        return ErrorEval.GetText(cell.ErrorCellValue).ChangeType<A>();
                    case CellType.Numeric:
                        if (DateUtil.IsCellDateFormatted(cell))
                        {
                            return cell.DateCellValue.ChangeType<A>();
                        }
                        else
                        {
                            return cell.NumericCellValue.ChangeType<A>();
                        }
                    case CellType.String:
                        string str = cell.StringCellValue;
                        if (string.IsNullOrEmpty(str))
                        {
                            return default(A);
                        }
                        else
                        {
                            return str.ChangeType<A>();
                        }
                    case CellType.Unknown:
                    case CellType.Blank:
                    default:
                        return default(A);
                }
            case CellType.Unknown:
            case CellType.Blank:
            default:
                return default(A);
        }
    }
}

 

类型转换

/// <summary>
/// 调用Convert.ChangeType
/// </summary>
/// <typeparam name="T">要返回的类型</typeparam>
/// <param name="token">待转换的值</param>
/// <returns>转换后的值</returns>
public static T ChangeType<T>(this object token)
{
    object result = ChangeType(token, typeof(T));
    if (result == null)
    {
        return default(T);
    }
    return (T)result;
}

/// <summary>
/// 把对象类型转换为指定类型
/// </summary>
/// <param name="value">要转换的值</param>
/// <param name="targetType">目标类型</param>
/// <returns> 转化后的指定类型的对象</returns>
public static object ChangeType(this object value, Type targetType)
{
    if (value == null)
    {
        return null;
    }
    if (targetType.IsNullableType())
    {
        targetType = targetType.GetUnderlyingType();
    }
    if (targetType.IsEnum)
    {
        return Enum.Parse(targetType, value.ToString());
    }
    if (targetType == typeof(Guid))
    {
        return Guid.Parse(value.ToString());
    }
    return Convert.ChangeType(value, targetType);
}

 

导出代码的主体部分

策略接口

/// <summary>
/// 提供每行数据的操作策略(不同的实现方式,达成不同的导入目标,存储目标不必一定是数据库)
/// 通过GetValue读取某单元格数据
/// </summary>
public interface ExcelImportHelper
{
     /// <summary>
     /// 判断本行数据是否数据库中已存在(有则会进行修改,没有则会新建)
     /// </summary>
     /// <param name="row">Excel中的某行数据</param>
     /// <returns>不存在则返回null,存在则返回该项数据</returns>
     T IsExist(IRow row);

    /// <summary>
    /// 新数据添加到数据库
    /// </summary>
    /// <param name="model">已完成映射的实体类实例</param>
    void Add(T model);

    /// <summary>
    /// 更新数据库中的已有数据
    /// </summary>
    /// <param name="model">已完成映射的实体类实例</param>
    void Update(T model);

    /// <summary>
    /// 提供从表格行数据映射到实体类的方法(解析失败的时候直接要抛出异常)
    /// </summary>
    /// <param name="row">Excel中的某行数据</param>
    /// <param name="model">新建的或刚从数据库中读取到的实体类实例</param>
    /// <returns>映射失败或数据为空时返回false,则不会录入数据库</returns>
    bool Map(IRow row, T model);
}

其他部分代码

/// <summary>
/// 表格导入数据库
/// 也可以是导入DataTable等形式,只要提供不同的策略
/// </summary>
/// <typeparam name="T">Model的类型</typeparam>
public class ExcelImport<T> where T : new()
{
    private ExcelImportHelper helper;

    /// <summary>
    /// 构造方法
    /// </summary>
    /// <param name="helper">操作策略</param>
    public ExcelImport(ExcelImportHelper helper)
    {
        this.helper = helper;
    }

    /// <summary>
    /// 处理结果
    /// </summary>
    public struct Result
    {
        private int num;           //导入行数
        private int num_add;       //新增行数
        private int num_edit;      //修改行数

        /// <summary>
        /// 导入行数
        /// </summary>
        public int Num
        {
            get
            {
                return num;
            }

            set
            {
                num = value;
            }
        }

        /// <summary>
        /// 新增行数
        /// </summary>
        public int Num_add
        {
            get
            {
                return num_add;
            }

            set
            {
                num_add = value;
            }
        }

        /// <summary>
        /// 修改行数
        /// </summary>
        public int Num_edit
        {
            get
            {
                return num_edit;
            }

            set
            {
                num_edit = value;
            }
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="num">导入行数</param>
        /// <param name="num_add">新增行数</param>
        /// <param name="num_edit">修改行数</param>
        internal Result(int num, int num_add, int num_edit)
        {
            this.num = num;
            this.num_add = num_add;
            this.num_edit = num_edit;
        }
    }

    #region 导入操作

    /// <summary>
    /// 表格导入到数据库
    /// </summary>
    /// <param name="name">上传控件的name</param>
    /// <param name="maxLength">最大上传的文件大小(MB)</param>
    /// <param name="headerRowsNum">表格头部所占的高度</param>
    /// <returns>表中的数据(只读取表中第一个Sheet)</returns>
    public Result Inport(string name, int maxLength, int headerRowsNum)
    {
        Stream stream = null;
        try
        {
            HttpContext context = HttpContext.Current;
            HttpRequest request = context.Request;

            //验证文件格式大小,返回文件流
            stream = GetInputStream(request, name, maxLength);

            //逐行读取文件内容并执行导入
            return Operation(stream, headerRowsNum);
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (stream != null)
            {
                stream.Close();
                stream.Dispose();
            }
        }
    }

    private Result Operation(Stream stream,int headerRowsNum)
    {
        //操作结果
        Result result = new Result(0, 0, 0);

        //读取表格内容
        try
        {
            using (stream)
            {
                //自动识别.xlsx(XSSFWorkbook),.xls(HSSFWorkbook)
                IWorkbook workbook = WorkbookFactory.Create(stream);

                if (workbook.NumberOfSheets == 0)
                    throw new Exception("报错信息:文件无数据");
                //取第一张表
                ISheet sheet = workbook.GetSheetAt(0);
                if (sheet.PhysicalNumberOfRows == 0)
                    throw new Exception("报错信息:文件无数据");

                //数据行数
                int rowCount = sheet.LastRowNum;

                //读取表中所有数据
                for (int i = sheet.FirstRowNum + headerRowsNum; i <= rowCount; i++)
                {
                    IRow row = sheet.GetRow(i);
                    if (row != null)
                    {
                        result.Num++;
                        T model = helper.IsExist(row);
                        if (model == null)
                        {
                            result.Num_add++;
                            //新建
                            model = new T();
                            bool ok = helper.Map(row, model);
                            if (ok)
                            {
                                helper.Add(model);
                            }
                        }
                        else
                        {
                            result.Num_edit++;
                            //修改
                            bool ok = helper.Map(row, model);
                            if (ok)
                            {
                                helper.Update(model);
                            }
                        }
                    }
                }
            }
            return result;
        }
        catch (Exception ex)
        {
            //在异常信息中添加出错位置
            throw new Exception("当前读取到第"+ result.Num + "行数据,已添加"+ result .Num_add+ "条,已更新" 
                + result.Num_edit + "条," + ex.Message);
        }
    }
    #endregion
}

调用

//策略
private class helper : ExcelImport<B_NEWS>.ExcelImportHelper
{
    public void Add(B_NEWS model)
    {
        bll.Add(model);
    }

    public B_NEWS IsExist(IRow row)
    {
        return null;
    }

    public bool Map(IRow row, B_NEWS model)
    {
        model.id = row.GetValue<int>(0);
        model.c_info_title = row.GetValue<string>(1);
        model.c_info_content = row.GetValue<string>(2);
        model.d_list_date = row.GetValue<DateTime>(3);
        model.d_add_date = row.GetValue<DateTime>(4);
        model.n_is_active = (row.GetValue<bool>(5) ? 1 : 0);
        model.int1 = row.GetValue<int>(6);
        return true;
    }

    public void Update(B_NEWS model)
    {
        bll.Update(model);
    }
}

protected void daoru(object sender, EventArgs e)
{
    new ExcelImport<B_NEWS>(new helper()).Inport("excel", 10, 2);
}

表格导出

调用者直接接触的操作类

public class ExcelExport<T>
{
    /// <summary>
    /// 每列数据的解析方法
    /// </summary>
    private List<Func<T, object>> func = new List<Func<T, object>>();

    private IExcelBuilder builder = new ExcelBuilder();

    private string headJson;

    /// <summary>
    /// 更换表格建造器
    /// </summary>
    /// <param name="builder">自定义的建造器</param>
    /// <returns></returns>
    public ExcelExport<T> ChangeBuilder(IExcelBuilder builder)
    {
        this.builder = builder;
        return this;
    }
    
    /// <summary>
    /// 定义列 
    /// </summary>
    /// <param name="convert">委托</param>
    /// <returns></returns>
    public ExcelExport<T> Column(Func<T, object> convert)
    {
        func.Add(convert);
        return this;
    }

    /// <summary>
    /// 设置Excel属性
    /// </summary>
    /// <param name="ext"></param>
    /// <returns></returns>
    public ExcelExport<T> SetExcelProperty(ExcelProperty ext)
    {
        builder.SetWorkbook(ext);
        return this;
    }

    /// <summary>
    /// 设置表头
    /// </summary>
    /// <param name="headJson">json形式的表头配置,可以配置多行表头</param>
    /// <returns></returns>
    public ExcelExport<T> SetExcelHeadJson(string headJson)
    {
        this.headJson = headJson;
        return this;
    }

    /// <summary>
    /// 设置表头
    /// </summary>
    /// <param name="path">绝对路径,内里保存json形式的表头配置</param>
    /// <returns></returns>
    public ExcelExport<T> SetExcelHeadFromFile(string path)
    {
        //读取配置信息
        this.headJson = File.ReadAllText(path);
        return this;
    }

    /// <summary>
    /// 设置表头
    /// </summary>
    /// <param name="headStr">“序号|订单号|订单状态|客户收货情况反馈|商品评价”的形式,仅支持单行表头</param>
    /// <returns></returns>
    public ExcelExport<T> SetExcelHeadStr(string headStr)
    {
        string[] head = headStr.Split('|');
        string headJson = "{\"root\":{\"head\":[";
        for (int i = 0, length = head.Length; i < length; i++)
        {
            if (i > 0)
            {
                headJson += ",";
            }
            headJson += "{";
            headJson += "\"text\":\"" + head [i]+ "\",";
            headJson += "\"cell_region\":\"0,0," + i + "," + i + "\"";
            headJson += "}";
        }
        headJson += "]";
        headJson += "}";
        headJson += "}";

        this.headJson = headJson;
        return this;
    }

    /// <summary>
    /// 导出WEB
    /// </summary>
    /// <param name="list">数据源(分组后的)</param>
    /// <param name="fileName">将要下载显示的名字</param>
    public void ExportToWeb(List<T> list, string fileName)
    {
        byte[] buffers = ForExport(list, fileName);
        ExportToWebExcel(buffers, fileName);
    }

    /// <summary>
    /// 导出到本地存储
    /// </summary>
    /// <param name="list">数据源(分组后的)</param>
    /// <param name="fileName">文件名称,请自己包含路径,例如C:\\test.xls</param>
    public void ExportToLocal(List<T> list, string fileName)
    {
        byte[] buffers = ForExport(list, fileName);
        ExportToLocalExcel(buffers, fileName);
    }

    #region private
    private byte[] ForExport(List<T> list, string fileName)
    {
        Check(list);
        
        //构建表格
        IWorkbook workbook = builder.BuildExcel<T>(list, headJson, func.ToArray());
        return SaveToByteArray(workbook);
    }

    private void Check(List<T> list)
    {
        //表头不算必填项
        //数据却不能为空
        if (list.Count == 0)
        {
            throw new Exception("数据源不能为空");
        }
    }

    /// <summary>
    /// 将WorkBook对象转换成内存流
    /// </summary>
    /// <param name="wookbook"></param>
    /// <returns></returns>
    private byte[] SaveToByteArray(IWorkbook wookbook)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            wookbook.Write(ms);
            ms.Flush();
            ms.Position = 0;
            return ms.GetBuffer();
        }
    }

    /// <summary>
    ///  本地存储到excel
    /// </summary>
    /// <param name="buffers">文件二进制流</param>
    /// <param name="fileName">文件目录例如C:\\test.xls</param>
    private void ExportToLocalExcel(byte[] buffers, string fileName)
    {
        using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
        {
            fs.Write(buffers, 0, buffers.Length);
            fs.Flush();
        }
    }

    /// <summary>
    /// web导出excel
    /// </summary>
    /// <param name="buffers">文件二进制流</param>
    /// <param name="fileName">文件名称</param>
    private void ExportToWebExcel(byte[] buffers, string fileName)
    {
        HttpResponse Response = HttpContext.Current.Response;

        Response.BufferOutput = false;
        Response.ContentEncoding = Encoding.UTF8;
        Response.Charset = "utf-8";

        Response.ContentType = "application/octet-stream";
        Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
        Response.AddHeader("Content-Length", buffers.Length.ToString());

        Response.Clear();
        Response.BinaryWrite(buffers);
        Response.End();
    }
    #endregion
}

  

表格样式配置

/**为方便样式书写,属性统一用小写*/

/// <summary>
/// 根节点, 定义Json表头的格式
/// </summary>
public class JsonSetting
{
    /// <summary>
    /// Root类
    /// </summary>
    public HeadInfo root { get; set; }
}

#region HeadInfo

/// <summary>
/// 报表表格头部信息
/// </summary>
public class HeadInfo
{
    /// <summary>
    /// 表头的样式
    /// </summary>
    public IList<Attribute4Head> head { get; set; }
    /// <summary>
    /// 每列单元格的样式
    /// </summary>
    public IList<Attribute4Cell> cell { get; set; }

    /// <summary>
    /// 表名,默认sheet
    /// </summary>
    public string sheet_name { get; set; }

    /// <summary>
    /// 默认单元格宽度(所有列),不设置则自适应宽度
    /// </summary>
    public int? default_width { get; set; }

    /// <summary>
    /// 默认行高度,不设置则使用表格的默认单元格高度
    /// </summary>
    public int? default_height { get; set; }

    /// <summary>
    /// 表格边框颜色 例如#000000
    /// </summary>
    public string border_color { get; set; }

    /// <summary>
    /// 边框风格,none,thin,dashed,dotted,double 默认 thin
    /// </summary>
    public string border_style { get; set; }

    /// <summary>
    /// 分组所在的列(索引从0开始:0,1)
    /// </summary>
    public string group_column { get; set; }
}
#endregion

/// <summary>
/// 关于表头单元格设置属性
/// </summary>
public class Attribute4Head : CellAttribute
{
    /// <summary>
    /// 单元格合并位置,(fromRow,toRow,fromColumn,toColumn)
    /// </summary>
    public string cell_region { get; set; }
    /// <summary>
    /// 显示的文字
    /// </summary>
    public string text { get; set; }
}

/// <summary>
/// 关于内容单元格设置属性
/// </summary>
public class Attribute4Cell : CellAttribute
{
    /// <summary>
    /// 数据格式(仅支持Excel的内嵌格式)
    /// </summary>
    public string data_format { get; set; }

    /// <summary>
    /// 宽度(内容单元格宽度覆盖默认宽度)
    /// </summary>
    public int? width { get; set; }
}

#region 公共属性
/// <summary>
/// 公共属性
/// </summary>
public abstract class CellAttribute
{
    /// <summary>
    /// 高度(限定行高,一行中只要一个单元格给定高度就可以了,多个单元格都有配置高度时,取最后一次赋值)
    /// </summary>
    public int? height { get; set; }
    /// <summary>
    /// 水平对齐方式 center,left,right
    /// </summary>
    public string align { get; set; }
    /// <summary>
    /// 垂直对齐方式center,top,bottom
    /// </summary>
    public string vertical_align { get; set; }
    /// <summary>
    /// 背景颜色.例如#000000
    /// </summary>
    public string background_color { get; set; }
    /// <summary>
    /// 前景颜色.例如#000000(单元格的背景色有bgcolor和forecolor两个背景色,一般使用forecolor)
    /// </summary>
    public string foreground_color { get; set; }
    /// <summary>
    /// 背景填充方式
    /// </summary>
    public string fill_pattern { get; set; }
    /// <summary>
    /// 字体大小
    /// </summary>
    public short? font_size { get; set; }
    /// <summary>
    /// 字体颜色
    /// </summary>
    public string font_color { get; set; }
    /// <summary>
    /// 字体名称,默认微软雅黑
    /// </summary>
    public string font_name { get; set; }
    /// <summary>
    ///是否是斜体
    /// </summary>
    public bool? italic { get; set; }
    /// <summary>
    /// 是否有中间线
    /// </summary>
    public bool? strike_out { get; set; }
    /// <summary>
    /// 是否设置下划线
    /// </summary>
    public bool? underline { get; set; }
    /// <summary>
    /// 表头文字是否加粗
    /// </summary>
    public bool? font_weight { get; set; }
}

样式解析

/// <summary>
/// 由字符样式读取相应的枚举值
/// </summary>
/// <typeparam name="T">枚举类型</typeparam>
/// <param name="str">字符串</param>
/// <param name="defaultValue">默认值</param>
/// <returns></returns>
private T ToEnumValue<T>(string str,T defaultValue)
{
    if (string.IsNullOrEmpty(str))
    {
        return defaultValue;
    }

    //不区分大小写
    str = str.Trim().ToLower();
    if (str == "0")
    {
        //输入的是数值
        return (T)Enum.Parse(typeof(T),"0");
    }
    else
    {
        var fields = typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public);
        int val = str.ToInt();
        if (val != 0 && val < fields.Length)
        {
            //输入的是数值
            return (T)Enum.Parse(typeof(T), str);
        }
        else
        {
            //输入的是枚举名
            foreach (var fi in fields)
            {
                var value = fi.GetValue(null);
                if(value.ToString().ToLower() == str)
                {
                    return (T)value;
                }
            }
            return defaultValue;
        }
    }
}

/// <summary>
/// 根据十六进制颜色获得颜色索引
/// </summary>
/// <param name="workbook"></param>
/// <param name="color"></param>
/// <returns></returns>
private short GetColorIndex(string color, HSSFWorkbook workbook)
{
    Color colour = ColorTranslator.FromHtml(color);

    if (this.XlPalette == null)
    {
        this.XlPalette = workbook.GetCustomPalette();
    }

    short s = 0;
    HSSFColor XlColour = XlPalette.FindColor(colour.R, colour.G, colour.B);
    if (XlColour == null)
    {
        XlColour = XlPalette.FindSimilarColor(colour.R, colour.G, colour.B);
        s = XlColour.Indexed;
    }
    else
    {
        s = XlColour.Indexed;
    }
    return s;
}

 涉及到的枚举类型

涉及到的枚举类型

 public enum FillPattern : short
{
    NoFill = 0,
    SolidForeground = 1,
    FineDots = 2,
    AltBars = 3,
    SparseDots = 4,
    ThickHorizontalBands = 5,
    ThickVerticalBands = 6,
    ThickBackwardDiagonals = 7,
    ThickForwardDiagonals = 8,
    BigSpots = 9,
    Bricks = 10,
    ThinHorizontalBands = 11,
    ThinVerticalBands = 12,
    ThinBackwardDiagonals = 13,
    ThinForwardDiagonals = 14,
    Squares = 15,
    Diamonds = 16,
    LessDots = 17,
    LeastDots = 18
}

public enum HorizontalAlignment
{
    General = 0,
    Left = 1,
    Center = 2,
    Right = 3,
    Fill = 4,
    Justify = 5,
    CenterSelection = 6,
    Distributed = 7
}

public enum VerticalAlignment
{
    None = -1,
    Top = 0,
    Center = 1,
    Bottom = 2,
    Justify = 3,
    Distributed = 4
}

public enum BorderStyle : short
{
    None = 0,
    Thin = 1,
    Medium = 2,
    Dashed = 3,
    Dotted = 4,
    Thick = 5,
    Double = 6,
    Hair = 7,
    MediumDashed = 8,
    DashDot = 9,
    MediumDashDot = 10,
    DashDotDot = 11,
    MediumDashDotDot = 12,
    SlantedDashDot = 13
}

  

表格建造器

    /// <summary>
    /// 表格建造器
    /// </summary>
    public interface IExcelBuilder
    {
        /// <summary>
        /// 更换样式解析器
        /// </summary>
        IExcelHelper Helper { set; }

        /// <summary>
        /// 构建表格
        /// </summary>
        /// <typeparam name="T">泛型实体</typeparam>
        /// <param name="list">要转换的列表</param>
        /// <param name="headJson">json形式的表头配置</param>
        /// <param name="fieldFuncs">字段委托</param>
        /// <returns></returns>
        HSSFWorkbook BuildExcel<T>(List<T> list, string headJson, Func<T, object>[] fieldFuncs);

        /// <summary>
        /// 设置excel文件基本属性
        /// </summary>
        /// <param name="ep"></param>
        void SetWorkbook(ExcelProperty ep);
    }

  

    /// <summary>
    /// 构建表格
    /// </summary>
    public class ExcelBuilder : IExcelBuilder
    {
        #region 字段及属性
        private const int RowPerSheet = 65530;                             //每张sheet最多数据行数
        private const int MaxColumnWidth = 50;                             //自适应列宽时的上限
        private string SheetName                                           //表名
        {
            get
            {
                return Helper.SheetName;
            }
        }
        private int HeadRow                                                //表头占据的行数
        {
            get
            {
                return Helper.HeadRow;
            }
        }

        /// <summary>
        /// 样式解析器
        /// </summary>
        public IExcelHelper Helper
        {
            set
            {
                this.helper = value;
            }
            private get
            {
                return helper;
            }
        }

        private HSSFWorkbook Workbook = new HSSFWorkbook();                //要导出的excel
        private IExcelHelper helper = new ExcelHelper();                   //用于解析属性
        private List<GroupClass> GroupColumn = new List<GroupClass>();     //分组的列的配置信息
        private List<CellRangeAddress> CellRange = new List<CellRangeAddress>(); //要合并的单元格
        private ISheet sheet = null;                                       //要导出的excel对象中的一个表
        #endregion

        #region IExcelBuilder

        /// <summary>
        /// 构建表格
        /// </summary>
        /// <typeparam name="T">泛型实体</typeparam>
        /// <param name="list">要转换的列表</param>
        /// <param name="headJson">json形式的表头配置</param>
        /// <param name="fieldFuncs">字段委托</param>
        /// <returns></returns>
        public HSSFWorkbook BuildExcel<T>(List<T> list, string headJson, Func<T, object>[] fieldFuncs)
        {
            //获取第一行数据
            List<object> dataRow = GetRowData(list[0], fieldFuncs);

            //解析第一行的数据,初步定下每列的默认样式
            Helper.GetStyle(headJson,dataRow, fieldFuncs, Workbook, GroupColumn);

            //写入数据
            Process(list, fieldFuncs);

            return Workbook;
        }

        /// <summary>
        /// 设置excel文件基本属性
        /// </summary>
        /// <param name="ep"></param>
        public void SetWorkbook(ExcelProperty ep)
        {
            DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
            dsi.Company = ep.Company;
            dsi.Manager = ep.Manager;
            dsi.Category = ep.Catagory;
            Workbook.DocumentSummaryInformation = dsi;
            SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
            si.Author = ep.Author;                    //填加xls文件作者信息
            si.ApplicationName = ep.ApplicationName;  //填加xls文件创建程序信息
            si.LastAuthor = ep.LastAuthor;            //填加xls文件最后保存者信息
            si.Comments = ep.Comments;                //填加xls文件作者信息
            si.Title = ep.Title;                      //填加xls文件标题信息
            si.Subject = ep.Subject;                  //填加文件主题信息
            si.Keywords = ep.KeyWord;
            si.CreateDateTime = DateTime.Now;
            si.Comments = ep.Comments;
            Workbook.SummaryInformation = si;
        }
        #endregion

        #region 完成从数据到excel的转化
        /// <summary>
        /// 整合数据
        /// </summary>
        /// <typeparam name="T">泛型实体</typeparam>
        /// <param name="list">要转换的列表</param>
        /// <param name="fieldFuncs">字段委托</param>
        private void Process<T>(List<T> list, Func<T, object>[] fieldFuncs)
        {
            //内容行
            int rowNum = -1;
            foreach (T item in list)
            {
                rowNum++;

                if ((rowNum % RowPerSheet) == 0)
                {
                    //新建sheet
                    NewSheet(rowNum);
                }

                //创建新行,获取数据
                int rowIndex = rowNum % RowPerSheet + HeadRow;
                IRow row = sheet.CreateRow(rowIndex);
                if (Helper.CellHeight.HasValue)
                {
                    //行高
                    row.HeightInPoints = Helper.CellHeight.Value;
                }
                List<object> dataRow = GetRowData(item, fieldFuncs);

                //写入
                int maxIndex = dataRow.Count;
                
                for (int colIndex = 0; colIndex < maxIndex; colIndex++)
                {
                    //bool,时间,字符串,数字
                    var val = dataRow[colIndex];
                    GroupClass groupClass = CheckGroup(colIndex);
                    if (groupClass == null)
                    {
                        ICell cell = row.CreateCell(colIndex);
                        WriteCell(row, cell, colIndex, val, fieldFuncs);
                    }
                    else
                    {
                        //分组
                        MergedRegionInColumn(groupClass, val, fieldFuncs, row, rowIndex, colIndex);
                    }
                }
            }

            //单元格合并
            foreach (var cellRange in CellRange)
            {
                sheet.AddMergedRegion(cellRange);
                //设置边框
                ((HSSFSheet)sheet).SetEnclosedBorderOfRegion(cellRange, Helper.WholeBorderStyle, Helper.WholeBorderColor);
            }
        }

        private void NewSheet(int rowNum)
        {
            int sheetIndex = (rowNum / RowPerSheet) + 1;
            sheet = Workbook.CreateSheet(SheetName + sheetIndex);
            //表头
            Helper.SetHeadAndDefaultStyle(Workbook, sheet);
            //新表新列
            for (int i = 0, length = GroupColumn.Count; i < length; i++)
            {
                GroupColumn[i].Value = null;
                GroupColumn[i].Count = 0;
                GroupColumn[i].cellRange = null;
            }
        }

        private void MergedRegionInColumn<T>(GroupClass groupClass,object val, Func<T, object>[] fieldFuncs, IRow row, int rowIndex, int colIndex)
        {
            object LastRowValue = groupClass.Value;
            //比对上一行的数据
            if (LastRowValue != null && LastRowValue.Equals(val))
            {
                //相等则合并单元格,行数累计

                //同一个单元格参与多次单元格合并,最终表格样式会出问题,需要先将旧的合并记录清掉
                CellRangeAddress lastCellRange = groupClass.cellRange;
                if (lastCellRange != null)
                {
                    CellRange.Remove(lastCellRange);
                }

                //新的合并配置
                groupClass.Count++;
                CellRangeAddress cellRange = new CellRangeAddress(rowIndex - groupClass.Count, rowIndex, colIndex, colIndex);
                CellRange.Add(cellRange);
                groupClass.cellRange = cellRange;
            }
            else
            {
                //不等则更新后续分组的信息
                for (int i = groupClass.Index, length = GroupColumn.Count; i < length; i++)
                {
                    GroupColumn[i].Value = null;
                    GroupColumn[i].Count = 0;
                    groupClass.cellRange = null;
                }
                groupClass.Value = val;
                //创建新单元格,普通写入操作
                ICell cell = row.CreateCell(colIndex);
                WriteCell(row, cell, colIndex, val, fieldFuncs);
            }
        }
        private void WriteCell<T>(IRow row, ICell cell,int colIndex,object val,Func<T, object>[] fieldFuncs)
        {
            ColumnInfo cellInfo = Helper.GetColumnInfo(colIndex);
            if (cellInfo == null)
            {
                cellInfo = Helper.AddColumn<T>(val, fieldFuncs, Workbook, sheet);
            }

            SetValue(cell, val);
            cell.CellStyle = cellInfo.Style;

            //调整列宽度
            if (cellInfo.Width == ColumnInfo.Auto)
            {
                int len = Encoding.GetEncoding(936).GetByteCount(val + "") + 8;
                if (len > MaxColumnWidth)
                {
                    len = MaxColumnWidth;
                }
                len = len * 256;
                if (sheet.GetColumnWidth(colIndex) < len)
                {
                    sheet.SetColumnWidth(colIndex, len);
                }
            }
        }

        #region 取值与填值

        /// <summary>
        /// 设置单元格的值
        /// </summary>
        /// <param name="cell"></param>
        /// <param name="val"></param>
        private void SetValue(ICell cell, object val)
        {
            if (val is bool)
            {
                var data = val.ChangeType<bool>();
                cell.SetCellValue(data);
            }
            else if (val is DateTime)
            {
                var data = val.ChangeType<DateTime>();
                cell.SetCellValue(data);
            }
            else if (val is double ||
             val is float ||
             val is long ||
             val is int ||
             val is short ||
             val is byte ||
             val is decimal)
            {
                var data = val.ChangeType<double>();
                cell.SetCellValue(data);
            }
            else
            {
                var data = val.ToString();
                cell.SetCellValue(data);
            }
        }

        /// <summary>
        /// 解析数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <param name="fieldFuncs"></param>
        /// <returns></returns>
        private List<object> GetRowData<T>(T item, Func<T, object>[] fieldFuncs)
        {
            List<object> dataRow = new List<object>();
            if (fieldFuncs.Length > 0)
            {
                for (int i = 0; i < fieldFuncs.Length; i++)
                {
                    dataRow.Add(fieldFuncs[i](item));
                }
            }
            else
            {
                if (item is DataRow)
                {
                    var row = item as DataRow;
                    foreach (DataColumn column in row.Table.Columns)
                    {
                        dataRow.Add(row[column]);
                    }
                }
                else if (item is IEnumerable<T>)
                {
                    foreach (var val in item as IEnumerable<T>)
                    {
                        dataRow.Add(val);
                    }
                }
                else
                {
                    throw new Exception("请添加从数据实例映射到表格行的方法");
                }
            }
            return dataRow;
        }

        #endregion

        /// <summary>
        /// 判断当前操作的列是不是要分组
        /// </summary>
        /// <param name="colIndex">列下表</param>
        /// <returns></returns>
        private GroupClass CheckGroup(int colIndex)
        {
            foreach (var item in GroupColumn)
            {
                if(item.Column == colIndex)
                {
                    return item;
                }
            }
            return null;
        }
        #endregion      
    }

 

表格样式解析器

 /// <summary>
    /// 表格样式解析器
    /// </summary>
    public interface IExcelHelper
    {
        /// <summary>
        /// 内容行的定高
        /// </summary>
        int? CellHeight { get; }

        /// <summary>
        /// 表头占据的行数
        /// </summary>
        int HeadRow { get; }

        /// <summary>
        /// 表名
        /// </summary>
        string SheetName { get; }

        /// <summary>
        /// 整个表格border样式
        /// </summary>
        short WholeBorderColor { get; }

        /// <summary>
        /// 整个表格border颜色
        /// </summary>
        BorderStyle WholeBorderStyle { get; }

        /// <summary>
        /// 比第一行数据多出的列
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="val"></param>
        /// <param name="fieldFuncs"></param>
        /// <param name="workbook"></param>
        /// <param name="sheet"></param>
        ColumnInfo AddColumn<T>(object val, Func<T, object>[] fieldFuncs, HSSFWorkbook workbook, ISheet sheet);

        /// <summary>
        /// 读取列配置
        /// </summary>
        /// <param name="index">列下标</param>
        /// <returns></returns>
        ColumnInfo GetColumnInfo(int index);

        /// <summary>
        /// 计算每一列的默认单元格样式
        /// </summary>
        void GetStyle<T>(string headJson, List<object> dataRow, Func<T, object>[] fieldFuncs, HSSFWorkbook workbook, List<GroupClass> groupList);

        /// <summary>
        /// 为新sheet设置表头和默认样式
        /// </summary>
        /// <param name="workbook"></param>
        /// <param name="sheet"></param>
        void SetHeadAndDefaultStyle(HSSFWorkbook workbook, ISheet sheet);
    }

 

    /// <summary>
    /// 解析表格样式
    /// </summary>
    public class ExcelHelper : IExcelHelper
    {
        #region 字段及属性
        private IList<Attribute4Head> CellStyle4Head = null;               //头部的配置信息
        private IList<Attribute4Cell> CellStyle4Cell = null;               //列配置信息
        private IList<ColumnInfo> columnInfo = new List<ColumnInfo>();     //记录解析后得到的每列的宽度及样式
        private string sheetName;                                          //表名
        private int headRow = 1;                                           //表头占据的行数
        private int  CellDefaultWidth;                                     //单元格宽度(默认值为ColumnInfo.Auto)
        private int? RowDefaultHeight;                                     //默认单元格高度(内容多了会自动撑高)
        private int? cellHeight;                                           //内容行的定高
        private BorderStyle wholeBorderStyle;                              //整个表格border样式,默认solid(thin)
        private short wholeBorderColor;                                    //整个表格border颜色
        private HSSFPalette XlPalette = null;                              //用于自定义颜色的对象(GetSetting中创建)

        /// <summary>
        /// 表名
        /// </summary>
        public string SheetName
        {
            get
            {
                return sheetName;
            }
        }

        /// <summary>
        /// 表头占据的行数
        /// </summary>
        public int HeadRow
        {
            get
            {
                return headRow;
            }
        }

        /// <summary>
        /// 内容行的定高
        /// </summary>
        public int? CellHeight
        {
            get
            {
                return cellHeight;
            }
        }

        /// <summary>
        /// 整个表格border样式
        /// </summary>
        public BorderStyle WholeBorderStyle
        {
            get
            {
                return wholeBorderStyle;
            }
        }

        /// <summary>
        /// 整个表格border颜色
        /// </summary>
        public short WholeBorderColor
        {
            get
            {
                return wholeBorderColor;
            }
        }
        #endregion

        #region 列配置操作

        /// <summary>
        /// 比第一行数据多出的列
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="val"></param>
        /// <param name="fieldFuncs"></param>
        /// <param name="workbook"></param>
        /// <param name="sheet"></param>
        public ColumnInfo AddColumn<T>(object val, Func<T, object>[] fieldFuncs, HSSFWorkbook workbook, ISheet sheet)
        {
            ColumnInfo info = GetDefaultCellStyle(val, fieldFuncs, workbook);
            columnInfo.Add(info);
            int index = columnInfo.Count - 1;
            UpdateColumn(index, workbook);
            //设置列宽
            if (info.Width != ColumnInfo.Auto)
            {
                sheet.SetColumnWidth(index, info.Width * 256);
            }
            return info;
        }

        /// <summary>
        /// 依据配置更新列配置
        /// </summary>
        /// <param name="index">列下标</param>
        /// <param name="workbook"></param>
        private void UpdateColumn(int index,HSSFWorkbook workbook)
        {
            ColumnInfo columnInfo = GetColumnInfo(index);
            if (columnInfo != null)
            {
                //列宽先赋值一个默认宽度
                columnInfo.Width = this.CellDefaultWidth;
                ICellStyle cellStyle = columnInfo.Style;
                //设置单元格边框
                cellStyle.BorderRight
                    = cellStyle.BorderLeft
                    = cellStyle.BorderBottom
                    = cellStyle.BorderTop
                    = WholeBorderStyle;
                cellStyle.BottomBorderColor
                       = cellStyle.RightBorderColor
                       = cellStyle.LeftBorderColor
                       = cellStyle.TopBorderColor
                       = WholeBorderColor;
                //更新样式
                Attribute4Cell style = null;
                if (CellStyle4Cell != null && CellStyle4Cell.Count > index)
                {
                    style = CellStyle4Cell[index];
                }
                if (style != null)
                {
                    //数据格式
                    if (!string.IsNullOrEmpty(style.data_format))
                    {
                        cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat(style.data_format);
                    }
                    //列宽
                    if (style.width.HasValue)
                    {
                        columnInfo.Width = style.width.Value;
                    }
                    //高度
                    if (style.height.HasValue)
                    {
                        this.cellHeight = style.height.Value;
                    }

                    //其他属性
                    AdaperCellStyle(cellStyle, style, workbook);
                }
            }
        }

        /// <summary>
        /// 读取列配置
        /// </summary>
        /// <param name="index">列下标</param>
        /// <returns></returns>
        public ColumnInfo GetColumnInfo(int index)
        {
            if (columnInfo.Count > index)
            {
                return columnInfo[index];
            }
            return null;
        }
        #endregion

        #region 解析样式

        /// <summary>
        /// 计算每一列的默认单元格样式
        /// </summary>
        public void GetStyle<T>(string headJson, List<object> dataRow, Func<T, object>[] fieldFuncs, HSSFWorkbook workbook, List<GroupClass> groupList)
        {
            // 读取第一行数据,为每列解析默认样式,依序加入cellStyle4Cell
            GetDefaultCellStyle(dataRow, fieldFuncs, workbook);

            //解析headJson
            GetSetting(headJson, workbook, groupList);
        }

        /// <summary>
        /// 依据一行示例数据为每列解析默认样式,依序加入cellStyle4Cell
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataRow"></param>
        /// <param name="fieldFuncs"></param>
        /// <param name="workbook"></param>
        private void GetDefaultCellStyle<T>(List<object> dataRow, Func<T, object>[] fieldFuncs, IWorkbook workbook)
        {
            for (int colIndex = 0; colIndex < dataRow.Count; colIndex++)
            {
                var val = dataRow[colIndex];
                ColumnInfo info = GetDefaultCellStyle(val, fieldFuncs, workbook);
                columnInfo.Add(info);
            }
        }
        /// <summary>
        /// //依据每个单元格对应的数据的数据类型计算出每列的默认样式,列的宽度设为自动
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="val"></param>
        /// <param name="fieldFuncs"></param>
        /// <param name="workbook"></param>
        /// <returns></returns>
        private ColumnInfo GetDefaultCellStyle<T>(object val, Func<T, object>[] fieldFuncs, IWorkbook workbook)
        {
            ICellStyle cellStyle;
            if (val is bool)
            {
                cellStyle = GetCellStyle(workbook, "默认");
            }
            else if (val is DateTime)
            {
                var data = val.ChangeType<DateTime>();
                if (data.Hour == 0 && data.Minute == 0 && data.Second == 0)
                {
                    cellStyle = GetCellStyle(workbook, "时间");
                }
                else
                {
                    cellStyle = GetCellStyle(workbook, "时间2");
                }
            }
            else if (val is double ||
             val is float ||
             val is long ||
             val is int ||
             val is short ||
             val is byte ||
             val is decimal)
            {
                var data = val.ChangeType<double>();
                if ((val + "").IndexOf(".") > 0)
                {
                    cellStyle = GetCellStyle(workbook, "数字");
                }
                else
                {
                    cellStyle = GetCellStyle(workbook, "数字2");
                }
            }
            else
            {
                cellStyle = GetCellStyle(workbook, "默认");
            }

            return new ColumnInfo() { Style = cellStyle, Width = ColumnInfo.Auto };
        }

        /// <summary>
        /// 解析json配置
        /// </summary>
        /// <param name="headJson">json字符串</param>
        /// <param name="workbook"></param>
        /// <param name="groupList"></param>
        private void GetSetting(string headJson, HSSFWorkbook workbook, List<GroupClass> groupList)
        {
            JsonSetting T = headJson.ToObject<JsonSetting>();
            //DebugUtils.Log(new MT.Business.Json().Convert2Json(T));
            //==========

            //分组的列信息
            GetGroupCellSetting(T.root.group_column, groupList);

            //表名
            this.sheetName = T.root.sheet_name;
            if (string.IsNullOrEmpty(this.sheetName))
            {
                this.sheetName = "sheet";
            }

            //默认单元格高度
            this.RowDefaultHeight = T.root.default_height;
            //边框样式
            this.wholeBorderStyle = ToEnumValue<BorderStyle>(T.root.border_style, BorderStyle.Thin);
            //边框颜色
            this.wholeBorderColor = GetColorIndex(T.root.border_color, workbook);

            //表头样式
            CellStyle4Head = T.root.head;
            //单元格样式
            CellStyle4Cell = T.root.cell;
            //默认单元格宽度
            this.CellDefaultWidth = (T.root.default_width.HasValue ? T.root.default_width.Value : ColumnInfo.Auto);

            //修正每列的配置信息
            for (int i = 0, length = this.columnInfo.Count; i < length; i++)
            {
                UpdateColumn(i, workbook);
            }
        }

        /// <summary>
        /// 初始化分组统计
        /// </summary>
        private void GetGroupCellSetting(string groupColumn, List<GroupClass> list)
        {
            int[] group = (string.IsNullOrEmpty(groupColumn) ? null : ToIntArray(groupColumn.Split(',')));
            if (group != null)
            {
                //依列下标排序
                group = group.OrderBy(x => x).ToArray();
                for (int i = 0, length = group.Length; i < length; i++)
                {
                    list.Add(new GroupClass { Column = group[i], Count = 0, Index = i });
                }
            }
        }

        #endregion

        #region 为新sheet设置表头和默认样式等

        /// <summary>
        /// 设置表头和默认样式
        /// </summary>
        /// <param name="workbook"></param>
        /// <param name="sheet"></param>
        public void SetHeadAndDefaultStyle(HSSFWorkbook workbook, ISheet sheet)
        {
            sheet.DisplayGridlines = true;
            if(this.CellDefaultWidth != ColumnInfo.Auto)
            {
                //默认单元格宽度
                sheet.DefaultColumnWidth = this.CellDefaultWidth;
            }
            if (this.RowDefaultHeight.HasValue)
            {
                //设置表格默认行高
                sheet.DefaultRowHeight = (short)(this.RowDefaultHeight.Value * 20);
            }

            //给定的列宽
            for (int i = 0, length = this.columnInfo.Count; i < length; i++)
            {
                var info = this.columnInfo[i];
                if (info.Width != ColumnInfo.Auto)
                {
                    sheet.SetColumnWidth(i, info.Width * 256);
                }
            }
            //写入表头
            SetHead(workbook,sheet);
        }

        /// <summary>
        /// 设置表头
        /// </summary>
        /// <param name="workbook"></param>
        /// <param name="sheet"></param>
        private void SetHead(HSSFWorkbook workbook, ISheet sheet)
        {
            List<IRow> rowList = new List<IRow>();
            //创建行
            for (int i = 0; i < HeadRow; i++)
            {
                IRow temp = sheet.CreateRow(i);
                rowList.Add(temp);
            }

            for (int i = 0; i < CellStyle4Head.Count; i++)
            {
                Attribute4Head attribute4Head = CellStyle4Head[i];
                int[] c = ToIntArray(attribute4Head.cell_region.Split(','));
                
                //计算title要插入的位置的索引
                int txtIndex = -1;
                int txtRow = -1;
                if ((c[0] <= c[1] && c[2] <= c[3]))
                {
                    #region 写入表头
                    //表头所占的列数
                    int _headRow = c[1] + 1;
                    if (headRow<= _headRow)
                    {
                        //创建行
                        for (int j = headRow; j < _headRow; j++)
                        {
                            IRow temp = sheet.CreateRow(j);
                            rowList.Add(temp);
                        }
                        headRow = _headRow;
                    }

                    //@ 合并单元格
                    if (c[0] < c[1] || c[2] < c[3])
                    {
                        //例如1,1,2,2 第二行中的第3列,例如1,1,2,7 第二行中的(第3列到8列),合并列
                        CellRangeAddress cellRange = new CellRangeAddress(c[0], c[1], c[2], c[3]);
                        sheet.AddMergedRegion(cellRange);
                        //设置边框
                        ((HSSFSheet)sheet).SetEnclosedBorderOfRegion(cellRange, WholeBorderStyle, WholeBorderColor);
                    }

                    //@ 填充内容
                    txtIndex = c[2];
                    txtRow = c[0];
                    ICell cell1 = rowList[txtRow].CreateCell(txtIndex);

                    cell1.SetCellValue(attribute4Head.text);
                    cell1.CellStyle = GetHeadCellStyle(workbook, attribute4Head);

                    //高度
                    if (attribute4Head.height.HasValue)
                    {
                        rowList[txtRow].HeightInPoints = attribute4Head.height.Value;
                    }
                    #endregion
                }
            }
            
        }

        private ICellStyle GetHeadCellStyle(HSSFWorkbook workbook,Attribute4Head cellStyle)
        {
            ICellStyle headStyle = workbook.CreateCellStyle();
            //设置单元格边框
            headStyle.BorderRight
                = headStyle.BorderLeft
                = headStyle.BorderBottom
                = headStyle.BorderTop
                = WholeBorderStyle;
            headStyle.BottomBorderColor
                   = headStyle.RightBorderColor
                   = headStyle.LeftBorderColor
                   = headStyle.TopBorderColor
                   = WholeBorderColor;
            //默认样式
            //水平对齐
            headStyle.Alignment = HorizontalAlignment.Center;

            //垂直对齐
            headStyle.VerticalAlignment = VerticalAlignment.Center;

            IFont font = workbook.CreateFont();
            //字体大小
            font.FontHeightInPoints = 12;
            //字体颜色
            font.Color = 8; //默认黑色
            //字体名称
            font.FontName = "微软雅黑";
            //加粗
            font.Boldweight = (short)FontBoldWeight.Bold;
            headStyle.SetFont(font);

            AdaperCellStyle(headStyle, cellStyle, workbook);
            return headStyle;
        }

        #endregion

        #region 字符串To 样式

        /// <summary>
        /// 由字符样式读取响应的枚举值
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="str">字符串</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns></returns>
        private T ToEnumValue<T>(string str,T defaultValue)
        {
            if (string.IsNullOrEmpty(str))
            {
                return defaultValue;
            }

            //不区分大小写
            str = str.Trim().ToLower();
            if (str == "0")
            {
                //输入的是数值
                return (T)Enum.Parse(typeof(T),"0");
            }
            else
            {
                var fields = typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public);
                int val = str.ToInt();
                if (val != 0 && val < fields.Length)
                {
                    //输入的是数值
                    return (T)Enum.Parse(typeof(T), str);
                }
                else
                {
                    //输入的是枚举名
                    foreach (var fi in fields)
                    {
                        var value = fi.GetValue(null);
                        if(value.ToString().ToLower() == str)
                        {
                            return (T)value;
                        }
                    }
                    return defaultValue;
                }
            }
        }

        /// <summary>
        /// 根据十六进制颜色获得颜色索引
        /// </summary>
        /// <param name="workbook"></param>
        /// <param name="color"></param>
        /// <returns></returns>
        private short GetColorIndex(string color, HSSFWorkbook workbook)
        {
            Color colour = ColorTranslator.FromHtml(color);

            if (this.XlPalette == null)
            {
                this.XlPalette = workbook.GetCustomPalette();
            }

            short s = 0;
            HSSFColor XlColour = XlPalette.FindColor(colour.R, colour.G, colour.B);
            if (XlColour == null)
            {
                XlColour = XlPalette.FindSimilarColor(colour.R, colour.G, colour.B);
                s = XlColour.Indexed;
            }
            else
            {
                s = XlColour.Indexed;
            }
            return s;
        }
        #endregion

        #region utils

        /// <summary>
        /// 依据用户json配置调整样式(公共部分)
        /// </summary>
        /// <param name="defaultCellStyle">默认样式</param>
        /// <param name="cellStyle">json传入的配置信息</param>
        /// <param name="workbook"></param>
        private void AdaperCellStyle(ICellStyle defaultCellStyle, CellAttribute cellStyle, HSSFWorkbook workbook)
        {
            //水平对齐
            if (!string.IsNullOrEmpty(cellStyle.align))
            {
                defaultCellStyle.Alignment = ToEnumValue<HorizontalAlignment>(cellStyle.align, HorizontalAlignment.Center);
            }

            //垂直对齐
            if (!string.IsNullOrEmpty(cellStyle.vertical_align))
            {
                defaultCellStyle.VerticalAlignment = ToEnumValue<VerticalAlignment>(cellStyle.vertical_align, VerticalAlignment.Center);
            }

            //背景颜色
            if (!string.IsNullOrEmpty(cellStyle.background_color) || !string.IsNullOrEmpty(cellStyle.foreground_color))
            {
                //重复设置背景色,有时候颜色会叠加,这里并不是简单的更换新值……
                //defaultCellStyle.FillForegroundColor = HSSFColor.White.Index;
                //defaultCellStyle.FillBackgroundColor = HSSFColor.Maroon.Index;
                defaultCellStyle.FillPattern = ToEnumValue<FillPattern>(cellStyle.fill_pattern, FillPattern.SolidForeground);
                if (!string.IsNullOrEmpty(cellStyle.background_color))
                {
                    //背景色
                    defaultCellStyle.FillBackgroundColor = GetColorIndex(cellStyle.background_color, workbook);

                }
                if (!string.IsNullOrEmpty(cellStyle.foreground_color))
                {
                    //前景色
                    defaultCellStyle.FillForegroundColor = GetColorIndex(cellStyle.foreground_color, workbook);
                }
            }

            IFont font = defaultCellStyle.GetFont(workbook);
            //字体大小
            if (cellStyle.font_size.HasValue)
            {
                font.FontHeightInPoints = cellStyle.font_size.Value; //设置字体大小
            }
            //字体颜色
            if (!string.IsNullOrEmpty(cellStyle.font_color))
            {
                font.Color = GetColorIndex(cellStyle.font_color, workbook);
            }
            //字体名称
            if (!string.IsNullOrEmpty(cellStyle.font_name))
            {
                font.FontName = cellStyle.font_name;
            }
            //是否是斜体
            if (cellStyle.italic.HasValue)
            {
                font.IsItalic = cellStyle.italic.Value ? true : false;
            }
            //是否有中间线
            if (cellStyle.strike_out.HasValue)
            {
                font.IsStrikeout = cellStyle.strike_out.Value ? true : false;
            }
            //是否设置下划线
            if (cellStyle.underline.HasValue)
            {
                font.Underline = cellStyle.underline.Value ? FontUnderlineType.Single : FontUnderlineType.None;
            }
            //是否加粗
            if (cellStyle.font_weight.HasValue)
            {
                font.Boldweight = cellStyle.font_weight.Value ? (short)FontBoldWeight.Bold : (short)FontBoldWeight.None;
            }
        }

        /// <summary>
        /// 获取默认样式
        /// </summary>
        /// <param name="wb">IWorkbook</param>
        /// <param name="str">标识</param>
        /// <returns></returns>
        private ICellStyle GetCellStyle(IWorkbook wb, string str)
        {
            ICellStyle cellStyle = wb.CreateCellStyle();
            IFont font = wb.CreateFont();

            //字体
            font.FontName = "微软雅黑";

            //居中对齐        
            cellStyle.Alignment = HorizontalAlignment.Center;
            //垂直对齐
            cellStyle.VerticalAlignment = VerticalAlignment.Center;

            //自动换行
            cellStyle.WrapText = true;

            //缩进
            cellStyle.Indention = 0;
            IDataFormat datastyle = wb.CreateDataFormat();
            switch (str)
            {
                /*
                  HSSFDataFormat.GetBuiltinFormat("0.00") 与 datastyle.GetFormat("yyyy/mm/dd"):
                  前者调用的是Excel的内嵌格式
                */
                case "时间":
                    cellStyle.DataFormat = datastyle.GetFormat("yyyy/mm/dd");
                    cellStyle.SetFont(font);
                    break;
                case "时间2":
                    cellStyle.DataFormat = datastyle.GetFormat("yyyy/mm/dd HH:mm");
                    cellStyle.SetFont(font);
                    break;
                case "数字":
                    cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00");
                    cellStyle.SetFont(font);
                    break;
                case "数字2":
                    cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0");
                    cellStyle.SetFont(font);
                    break;
                case "钱":
                    cellStyle.DataFormat = datastyle.GetFormat("¥#,##0");
                    cellStyle.SetFont(font);
                    break;
                case "url":
                    font.Underline = FontUnderlineType.Single;
                    font.Color = HSSFColor.OliveGreen.Blue.Index;
                    font.IsItalic = true;
                    cellStyle.SetFont(font);
                    cellStyle.Alignment = HorizontalAlignment.Center;
                    break;
                case "百分比":
                    cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00%");
                    cellStyle.SetFont(font);
                    break;
                case "中文大写":
                    cellStyle.DataFormat = datastyle.GetFormat("[DbNum2][$-804]0");
                    cellStyle.Alignment = HorizontalAlignment.Center;
                    cellStyle.SetFont(font);
                    break;
                case "科学计数法":
                    cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00E+00");
                    cellStyle.SetFont(font);
                    break;
                case "默认":
                    cellStyle.SetFont(font);
                    cellStyle.Alignment = HorizontalAlignment.Center;
                    cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("@");//全部做字符串处理
                    break;
            }
            return cellStyle;
        }

        /// <summary>
        /// 字符串数组to整型数组
        /// </summary>
        /// <param name="region">字符串数组</param>
        /// <returns></returns>
        private int[] ToIntArray(string[] region)
        {
            ArrayList aList = new ArrayList();
            foreach (string i in region)
            {
                aList.Add(Convert.ToInt32(i));
            }
            return (int[])aList.ToArray(typeof(int));
        }
        #endregion
    }

调用

    public class ExamEntity
    {
        public int Id { get; set; }
        /// <summary>
        /// 学生姓名
        /// </summary>
        public string Name { get; set; }
        public bool Sex { get; set; }
        /// <summary>
        /// 考试时间,每次考试时间
        /// </summary>
        public DateTime ExamTime { get; set; }
        /*各科成绩,语数英 物化生*/
        public int Chinese { get; set; }
        public int English { get; set; }
        public int Math { get; set; }
        public int Physics { get; set; }
        public int Chemistry { get; set; }
        public int Biology { get; set; }
        /// <summary>
        /// 总分
        /// </summary>
        public int SumCount { get; set; }

    }
    public List<ExamEntity> exam = new List<ExamEntity> {
          new ExamEntity{Id=1,Name="张三",ExamTime=Convert.ToDateTime("2013-03-01 08:30:00"),Chinese=122,English=111,Math=90,Physics=50,Chemistry=80,Biology=40,SumCount=493},
          new ExamEntity{Id=1,Name="张三",ExamTime=Convert.ToDateTime("2013-04-01 08:30:00"),Chinese=109,English=100,Math=100,Physics=90,Chemistry=70,Biology=60,SumCount=529},
          new ExamEntity{Id=1,Name="张三",ExamTime=Convert.ToDateTime("2013-05-01 08:30:00"),Chinese=109,English=100,Math=100,Physics=90,Chemistry=70,Biology=60,SumCount=529},
           new ExamEntity{Id=2,Name="李四",ExamTime=Convert.ToDateTime("2013-03-01 08:30:00"),Chinese=122,English=111,Math=90,Physics=50,Chemistry=80,Biology=40,SumCount=493},
          new ExamEntity{Id=2,Name="李四",ExamTime=Convert.ToDateTime("2013-04-01 08:30:00"),Chinese=109,English=100,Math=100,Physics=90,Chemistry=70,Biology=60,SumCount=529},
          new ExamEntity{Id=2,Name="李四",ExamTime=Convert.ToDateTime("2013-05-01 08:30:00"),Chinese=109,English=100,Math=100,Physics=90,Chemistry=70,Biology=60,SumCount=529},
          new ExamEntity{Id=3,Name="王五",ExamTime=Convert.ToDateTime("2013-03-01 08:30:00"),Chinese=122,English=111,Math=90,Physics=50,Chemistry=80,Biology=40,SumCount=493},
          new ExamEntity{Id=3,Name="王五",ExamTime=Convert.ToDateTime("2013-04-01 08:30:00"),Chinese=109,English=100,Math=100,Physics=90,Chemistry=70,Biology=60,SumCount=529},
          new ExamEntity{Id=4,Name="陈流",ExamTime=Convert.ToDateTime("2013-05-01 08:30:00"),Chinese=109,English=100,Math=100,Physics=90,Chemistry=70,Biology=60,SumCount=529}
        };
    protected void daochu(object sender, EventArgs e)
    {
        string json = @"{ 'root':{'sheet_name':'学生成绩','default_width':12,'group_column': '0,1,2,3','head':[ {
                                                                       'text':'编号',
                                                                       'height':54,
                                                                      'cell_region':'0,2,0,0'
                                                                   },
                                                                  {
                                                                      'text':'学生姓名',
                                                                      'cell_region':'0,2,1,1'
                                                                 },
                                                                    {
                                                                      'text':'性别',
                                                                      'cell_region':'0,2,2,2'
                                                                 }, {
                                                                      'text':'考试时间',
                                                                      'cell_region':'0,2,3,3'
                                                                 }, {
                                                                      'text':'主科目',
 'height':18,
                                                                      'cell_region':'0,0,4,6'
                                                                 }, {
                                                                      'text':'副科目',
                                                                      'cell_region':'0,1,7,9'
                                                                 }, 
                                                                     {
                                                                      'text':'必修课',
                                                                    'height':18,
                                                                      'cell_region':'1,1,4,5'
                                                                 }, {
                                                                      'text':'选修课',
                                                                      'cell_region':'1,1,6,6'
                                                                 }, 
                                                                {
                                                                      'text':'语文',
                                                                      'height':18,  
                                                                      'cell_region':'2,2,4,4'
                                                                 }, {
                                                                      'text':'数学',
                                                                      'cell_region':'2,2,5,5'
                                                                 }, {
                                                                      'text':'英语',
                                                                      'cell_region':'2,2,6,6'
                                                                 }, {
                                                                      'text':'物理',
                                                                      'cell_region':'2,2,7,7'
                                                                 }, {
                                                                      'text':'化学',
                                                                      'cell_region':'2,2,8,8'
                                                                 }, {
                                                                      'text':'生物',
                                                                      'cell_region':'2,2,9,9'
                                                                 }, {
                                                                      'text':'总分',
                                                                      'cell_region':'0,2,10,10'
                                                                 }
                                                                    ],
                                                               'cell':[{},{},{},{'width':30}]
                                                                }
                                                               }";
        //处理数据源,对要分组的几列进行排序(order by Name,ExamTime)
        List<ExamEntity> exams = exam.OrderByDescending(x => x.Name).ThenByDescending(x => x.ExamTime).ToList<ExamEntity>();

        new ExcelExport<ExamEntity>()
                    //.SetExcelHeadStr(headStr)
                    .SetExcelHeadJson(json)
                    .Column(a => a.Id)
                    .Column(a => a.Name)
                    .Column(a => a.Sex ? "男" : "女")
                    .Column(a => a.ExamTime)
                    .Column(a => a.Chinese)
                    .Column(a => a.Math)
                    .Column(a => a.English)
                    .Column(a => a.Physics)
                    .Column(a => a.Chemistry)
                    .Column(a => a.Biology)
                    .Column(a => a.SumCount)
                    .ExportToWeb(exams, "daochu.xls");
    }

 

posted @ 2016-05-31 00:21  随心~  阅读(950)  评论(0编辑  收藏  举报