轮子 · DotNET · 一个后台生成Excel导出的方法

使用

调用方法

通过ExcelsList.fm生成一个处理数据的方法,此处用的lambdaExcelsList的构造方法里,必须传的是列名,其他的如果没有就空着,下载的文件名无所谓,前台用的时候也可以给名字

    DataTable ListData = 各种获取数据;

     
    //列的信息
    List dc=new List();
    ExcelsList.fm isend = (string cellname,DataRow rows) =>
    {
        if (rows[cellname].ToString() == "1") return "待化解";
        if (rows[cellname].ToString() == "2") return "已化解";
        return "";
    };
    ExcelsList.fm getstate= (string cellname,DataRow rows)=> { 
        if (rows["isend"].ToString() == "1") { // 未办结
            if (DateTime.Now.AddDays(Convert.ToInt32(rows["LimitDays"])) < Convert.ToDateTime(rows[cellname]))
            {
                //return "超期未办结";
                return "超期未办结";
            }
            else if (DateTime.Now.AddDays(Convert.ToInt32(rows["LimitDays"]) * 2 / 3) < Convert.ToDateTime(rows[cellname]))
            {
                //return "黄色预警";
                return "黄色预警";
            }
            else
            {   //化解中
                return "化解中";
            }
        } else {     
            return "已办结";
        }
    };
    //添加所有显示的列
    dc.Add(new ExcelsList("pctime", "状态", getstate));
    dc.Add(new ExcelsList("id", "排查编号"));
    dc.Add(new ExcelsList("pctime", "排查时间"));
    dc.Add(new ExcelsList("name", "信访人姓名"));
    dc.Add(new ExcelsList("addorg", "排查单位"));
    dc.Add(new ExcelsList("nowexeorg", "承办单位"));
    dc.Add(new ExcelsList("handlemode", "办理方式"));
    dc.Add(new ExcelsList("isend", "是否化解", isend)); 

    //导出   
    HPK.Utilities.DeriveExcel.DataTableandExcelsListToExcel(Response, ListData, dc, "化解" + DateTime.Now.ToString("yyyy-MM-dd HHmmss"));
复制代码

前台

这边千变万化的,具体情况具体对待,这里先记下一种

调用写在MVC的Controller里的方法

var a = document.createElement("a");
a.href = "url"; 
a.download = '化解' + formatDate(new Date(), "yyyy-MM-dd-hhmmss.xls"); //如果不填就是后台默认的名字
a.click();
复制代码

实现导出的部分

封装类

用来保存真实列名、显示列名和处理内容的方法

/// 
/// 列的信息
/// 
public class ExcelsList
{

    #region  封装字段
    //显示名称
    public string zh_name;

    //所在列名
    public string col_name;

    //过滤方法
    public fm thisfm;
    #endregion

    #region 方法
    /// 
    /// 导出excel列的信息
    /// 
    /// "_col">列名
    /// "_zh">列备注
    /// "_thisfm">处理值的方法
    public ExcelsList(string _col, string _zh = null, fm _thisfm = null)
    {
        this.col_name = _col;

        this.zh_name = _zh;

        this.thisfm = _thisfm;

    }
    /// 
    /// 过滤的方法
    /// 
    /// "str">输入值
    /// 返回一个方法
    public delegate string fm(string str,DataRow dr = null);

    /// 
    /// 获取筛选后的返回值的方法
    ///  
    /// 返回值
    public string retstr(DataRow ROW)
    {
        string str;

        ///是否过滤规则
        if (this.thisfm != null)
        {
            str = this.thisfm(this.col_name, ROW);
        }
        else
        {
            str = ROW[this.col_name].ToString();
        }

        ///是否规定格式
        if (!str.StartsWith("))
        {
            str = "" + str + "";
        }

        ///返回值
        return str;
    }
    #endregion

}
复制代码

后台

HttpResponseBase Response视情况可以不用传值进来,直接HttpContext.Current.Response

/// 
/// DataTable导出Excel
/// 
/// "data">数据源
/// "DataColumn">导出的字段设置
/// "fileName">文件名称&表头
public static void DataTableAndExcellistToExcel(HttpResponseBase Response, DataTable data, List DataColumn, string fileName="Excel")
{
    Response.ContentType = "application/vnd.ms-excel";
    Response.ContentEncoding = System.Text.Encoding.UTF8;
    Response.Charset = "Utf-8";
    Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName + ".xls", System.Text.Encoding.UTF8));//给一个默认的名字,如果前台没给名字,那下载时候就是显示这个
    StringBuilder sbHtml = new StringBuilder();
    sbHtml.AppendLine("");
    sbHtml.AppendLine("");
    sbHtml.AppendLine("");
    //表头
    sbHtml.AppendLine("");
    sbHtml.AppendLine("");
    sbHtml.AppendLine("");
    //写出列名
    sbHtml.AppendLine("");
    foreach (ExcelsList item in DataColumn)
    {
        sbHtml.AppendLine("");
    }
    sbHtml.AppendLine("");
    //写数据
    foreach (DataRow row in data.Rows)
    {
        sbHtml.Append("");
        foreach (ExcelsList item in DataColumn)
        {
            sbHtml.Append(item.retstr(row));
        }
        sbHtml.AppendLine("");
    }
    sbHtml.AppendLine("
+ DataColumn .Count.ToString()+ "\" style='height:37.00pt;width:942.75pt;border-right:none;border-bottom:none;' x:str>" + fileName + "
" + item.zh_name ?? item.col_name + "
"
); Response.Write(sbHtml.ToString()); Response.End(); } 复制代码

踩过的坑

1.导出的长串数字自动转换 科学计数法 显示

例如 201805241723197 ,会在excel 里显示为2.01805E+16,这个解决方法是

· x:str属性
有时候不太好用

str = " + str + "\">" + str + "";
复制代码

· MSO-NUMBER-FORMAT
这个可以用

str = "" + str + "";
复制代码

或者放进css里

sbHtml.AppendLine("");

...

str = "" + str + "";
复制代码

其他的MSO-NUMBER-FORMAT

mso-number-format:"0" NO Decimals   
mso-number-format:"0\.000" 3 Decimals   
mso-number-format:"\#\,\#\#0\.000" Comma with 3 dec   
mso-number-format:"mm\/dd\/yy" Date7   
mso-number-format:"mmmm\ d\,\ yyyy" Date9   
mso-number-format:"m\/d\/yy\ h\:mm\ AM\/PM" D -T AMPM   
mso-number-format:"Short Date" 01/03/1998   
mso-number-format:"Medium Date" 01-mar-98   
mso-number-format:"d\-mmm\-yyyy" 01-mar-1998   
mso-number-format:"Short Time" 5:16   
mso-number-format:"Medium Time" 5:16 am   
mso-number-format:"Long Time" 5:16:21:00   
mso-number-format:"Percent" Percent - two decimals   
mso-number-format:"0%" Percent - no decimals   
mso-number-format:"0\.E+00" Scientific Notation   
mso-number-format:"\@" Text   
mso-number-format:"\#\ ???\/???" Fractions - up to 3 digits (312/943)  
复制代码

2.Response.End()不知道为什么总是报错

从网上搜来的内容

Response.End()是终止服务器输出,但有可能会throw出线程异常,不处理即可,ms官方对该问题进行了解释,如果你不希望throw出线程错误,则可以采用相关解决方法。

HttpContext.Current.ApplicationInstance.CompleteRequest();代替后解决了

你可能感兴趣的:(测试)