云智博客-blog

云智企业管理信息系统官方博客

云计算之IAAS,SAAS,PAAS:云智属于PAAS

云服务只是一个统称,可以分成三大类。 

  • IaaS:基础设施服务,Infrastructure-as-a-service
  • PaaS:平台服务,Platform-as-a-service
  • SaaS:软件服务,Software-as-a-service

它们有什么区别呢?我们举个烤披萨的例子。

方案一:On-Premises

在家自己做,这真是个麻烦事,你得有厨房,购置烤炉,煤气等基础设施,然后发面、做面团、进烤箱。。。

方案二:IaaS

他人提供厨房、炉子、煤气,你使用这些基础设施,来烤你的披萨。

方案二:PaaS

除了使用他人提供的基础设施设施外,连披萨也是从披萨店里买回成品,只需要烘焙就好了。

方案三:SaaS

到披萨店里面去吃披萨,啥都不用做。

那么对于软件来说,我们把它们分为三层:基础设施(infrastructure)、平台(platform)和软件(software)。这其实就是云计算的三个分层,基础设施在最下端,平台在中间,软件在顶端,分别是分别是Infrastructure-as-a-Service(IaaS),Platform-as-a-Service(PaaS),Software-as-a-Service(SaaS),别的一些“软”的层可以在这些层上面添加。

而你的公司什么都有,现在所处的状态叫本地部署(On-Premises),就像在自己家做披萨一样。你需要去买服务器,或者别的高昂的硬件来控制本地应用,让你的业务运行起来,这就叫本地部署。

假如你家BOSS突然有一天想明白了,只是为了吃上披萨而已,为什么非要自己做呢?于是,准备考虑一家云服务供应商,这个云服务供应商能提供哪些服务呢?其所能提供的云服务也就是云计算的三个分层:IaaS、PaaS和SaaS。
 
 
回到云智本身,我们使用的是阿里云的基础构架,即IaaS: Infrastructure-as-a-Service(基础设施即服务)

有了IaaS,我司将硬件外包到阿里云上去。IaaS公司会提供场外服务器,存储和网络硬件,我们租用,节省了维护成本和办公场地。

云智对外提供企业信息化管理软件,即SaaS: Software-as-a-Service(软件即服务),客户尽管使用我们的服务,无需准备硬件,也无需开发人员研发软件,我们提供服务的满足你的信息化需求。

 

云智系统金税接口

云智系统支持将销售账单生成金税xml文件,在航天和百望两大开票系统中测试通过.

云智系统还支持自定义开票,将excel转为xml文件,本文将介绍此功能.

首先,在云智系统中下载excel模板,在模板上填入增值税发票所开的内容项,其中客户代码为云智系统中的客户代码,需要在系统中维护此客户的开票信息(税号,银行账号).

然后在云智系统中选择此模板文件,点击导入

页面将展示两张发票信息,其中第二张发票里面有两条明细项.

再点击导出,则生产xml文件如下:

<?xml version="1.0" encoding="GBK" ?>
<Kp>
  <Version>2.0</Version>
  <Fpxx>
    <Zsl>2</Zsl>
    <Fpsj>
      <Fp>
        <Djh>B2017061701</Djh>
        <Gfmc>PIONEER ELECTRONICS(SHANGHAI EXPORT ZONE)CO.,LTD</Gfmc>
        <Gfsh />
        <Gfyhzh>外销发票无需资料</Gfyhzh>
        <Gfdzdh>电话:</Gfdzdh>
        <Bz />
        <Fhr>甲</Fhr>
        <Skr>乙</Skr>
        <Spbmbbh>12.0</Spbmbbh>
        <Hsbz>0</Hsbz>
        <Sgbz>0</Sgbz>
        <Spxx>
          <Sph>
            <Xh>1</Xh>
            <Spmc>门U</Spmc>
            <Ggxh>F390LBW80SEP2</Ggxh>
            <Jldw>个</Jldw>
            <Spbm>1090418990000000000</Spbm>
            <Qyspbm />
            <Syyhzcbz>0</Syyhzcbz>
            <Lslbz />
            <Yhzcsm />
            <Dj>47.55</Dj>
            <Sl>7</Sl>
            <Je>332.85</Je>
            <Slv>0.17</Slv>
            <Kce>0</Kce>
          </Sph>
        </Spxx>
      </Fp>
      <Fp>
        <Djh>B2017061702</Djh>
        <Gfmc>XXXXXXXXXX汽车部件(昆山)有限公司</Gfmc>
        <Gfsh>91320583XXXXXXXXX</Gfsh>
        <Gfyhzh>农行昆山城东支行5324010XXXXXXXXX</Gfyhzh>
        <Gfdzdh>江苏省昆山市开发区XXXXXXXXXX 电话:</Gfdzdh>
        <Bz />
        <Fhr>甲</Fhr>
        <Skr>乙</Skr>
        <Spbmbbh>12.0</Spbmbbh>
        <Hsbz>0</Hsbz>
        <Sgbz>0</Sgbz>
        <Spxx>
          <Sph>
            <Xh>1</Xh>
            <Spmc>水槽U</Spmc>
            <Ggxh>F060QBU01QP</Ggxh>
            <Jldw>个</Jldw>
            <Spbm>1090418990000000000</Spbm>
            <Qyspbm />
            <Syyhzcbz>0</Syyhzcbz>
            <Lslbz />
            <Yhzcsm />
            <Dj>10.09</Dj>
            <Sl>3</Sl>
            <Je>30.27</Je>
            <Slv>0.17</Slv>
            <Kce>0</Kce>
          </Sph>
          <Sph>
            <Xh>2</Xh>
            <Spmc>控制面板 喷涂</Spmc>
            <Ggxh>F80349L04SXP</Ggxh>
            <Jldw>个</Jldw>
            <Spbm>1090418990000000000</Spbm>
            <Qyspbm />
            <Syyhzcbz>0</Syyhzcbz>
            <Lslbz />
            <Yhzcsm />
            <Dj>8.6</Dj>
            <Sl>23</Sl>
            <Je>197.8</Je>
            <Slv>0.17</Slv>
            <Kce>0</Kce>
          </Sph>
        </Spxx>
      </Fp>
    </Fpsj>
  </Fpxx>
</Kp>

最后将此xml文件直接导入到金税系统中形成发票.

 

实现此功能的核心代码如下:

public Kp ReadKp(Stream inputStream)
{
    Kp kp = new Kp();
    if (inputStream.Length == 0)
    {
        throw new Exception("Import.Stream.Empty");
    }

    var workbook = WorkbookFactory.Create(inputStream);
    //var book = new XSSFWorkbook(inputStream);

    ISheet sheet = workbook.GetSheetAt(0);
    IEnumerator rows = sheet.GetRowEnumerator();

    #region template 1
    ImportHelper.JumpRows(rows, 1);

    #region 列定义
    int colDjh = 0;//单据号
    int colKh = 1;//客户代码
    int colBz = 2;//备注
    int colSpmc = 3;//商品名称
    int colGgxh = 4;//规格型号
    int colJldw = 5;//计量
    int colSpbm = 6;//商品编码
    int colSl = 7;//数量
    int colJe = 8;//金额
    int colSlv = 9;//税率

    #endregion
    List<Js> jsList = new List<Js>();
    int rowIndex = 0;
    int colIndex = 0;
    while (rows.MoveNext())
    {
        Js js = new Js();
        rowIndex++;
        var row = (IRow)rows.Current;
        if (!ImportHelper.CheckValidDataRow(row, 0, 9))
        {
            break;//边界
        }
        ICell cell = null;
        #region 读取
        try
        {
            js.Djh = ImportHelper.GetCellStringValue(row.GetCell(colDjh));
            if (js.Djh == null)
            {
                break;
            }
            js.Kh = ImportHelper.GetCellStringValue(row.GetCell(colKh));//客户代码
            js.Bz = ImportHelper.GetCellStringValue(row.GetCell(colBz));//备注
            js.Spmc = ImportHelper.GetCellStringValue(row.GetCell(colSpmc));//商品名称
            js.Ggxh = ImportHelper.GetCellStringValue(row.GetCell(colGgxh));//规格型号
            js.Jldw = ImportHelper.GetCellStringValue(row.GetCell(colJldw));//计量单位
            js.Spbm = ImportHelper.GetCellStringValue(row.GetCell(colSpbm));//商品编码
            js.Sl = ImportHelper.GetCellStringValue(row.GetCell(colSl));//数量
            js.Je = ImportHelper.GetCellStringValue(row.GetCell(colJe));//金额
            js.Slv = ImportHelper.GetCellStringValue(row.GetCell(colSlv));//税率

            if (js.Spmc == null)
            {
                cell = row.GetCell(colSpmc);
                throw new Exception("商品名称不能为空");
            }
            if (js.Ggxh == null)
            {
                cell = row.GetCell(colGgxh);
                throw new Exception("规格型号不能为空");
            }
            if (js.Jldw == null)
            {
                cell = row.GetCell(colJldw);
                throw new Exception("计量单位不能为空");
            }
            if (js.Spbm == null)
            {
                cell = row.GetCell(colSpbm);
                throw new Exception("商品编码不能为空");
            }
            else if (js.Spbm.Length != 19)
            {
                cell = row.GetCell(colSpbm);
                throw new Exception("商品编码应为19位编码");
            }


            if (js.Sl == null)
            {
                cell = row.GetCell(colSl);
                throw new Exception("数量不能为空");
            }
            else
            {
                double sl = 0;
                if (!double.TryParse(js.Sl, out sl))
                {
                    throw new Exception("数量不为数字");
                }
                if (sl == 0)
                {
                    throw new Exception("数量不能为0");
                }
            }

            if (js.Je == null)
            {
                cell = row.GetCell(colJe);
                throw new Exception("数量不能为空");
            }
            else
            {
                double je = 0;
                if (!double.TryParse(js.Je, out je))
                {
                    throw new Exception("金额不为数字");
                }
            }

            if (js.Slv == null)
            {
                cell = row.GetCell(colSlv);
                throw new Exception("数量不能为空");
            }
            else
            {
                double slv = 0;
                if (!double.TryParse(js.Slv, out slv))
                {
                    throw new Exception("税率不为数字");
                }
            }
        }
        catch (Exception ex)
        {
            ImportHelper.ThrowCommonError(rowIndex, colIndex, cell, ex.Message);
        }
        #endregion
        jsList.Add(js);
    }
    if (jsList.Count == 0)
    {
        throw new Exception("Import.Result.Error.ImportNothing");
    }
    #endregion
    kp = Js2Kp(jsList);
    return kp;
}

private Kp Js2Kp(List<Js> jsList)
{
    var jsGroupList = jsList.GroupBy(p => new { p.Djh, p.Kh }).ToList();
    //单据号	客户代码	备注	商品名称	规格型号	计量	商品编码	数量	金额	税率
    //Djh	Kh	Bz	Spmc	Ggxh	Jldw	Spbm	Sl	Je	Slv
    Kp kp = new Kp();

    kp.Version = "2.0";
    kp.Fpxx = new Fpxx();
    kp.Fpxx.Zsl = jsGroupList.Count.ToString();
    kp.Fpxx.Fpsj = new List<Fp>();

    var plant = this.entityDao.FindById<Plant>("P01");

    foreach (var jsGroup in jsGroupList)
    {
        var fp = new Fp();
        fp.Djh = jsGroup.Key.Djh;
        fp.Bz = (jsGroup.First().Bz ?? string.Empty);
        fp.Gfmc = string.Empty;
        fp.Gfsh = string.Empty;
        fp.Gfyhzh = string.Empty;
        fp.Gfdzdh = string.Empty;
        if (jsGroup.Key.Kh != null)
        {
            var customer = this.entityDao.FindById<Customer>(jsGroup.Key.Kh);
            if (customer != null)
            {
                var billAddress = this.entityDao.FindAll<BillAddress>(" from BillAddress b where b.Party=? ", customer.Code)[0];
                fp.Gfsh = billAddress.TaxID != null ? billAddress.TaxID.Trim() : string.Empty;
                fp.Gfyhzh = SubStr(billAddress.BankAccount != null ? billAddress.BankAccount.Trim() : "银行账号未维护", 100);
                fp.Gfdzdh = SubStr(string.Format("{0} 电话:{1}", billAddress.Address, billAddress.TelephoneNumber), 100);
            }
            fp.Gfmc = SubStr(customer.Name.Trim(), 100);
        }
        fp.Fhr = plant.Fhr;
        fp.Skr = plant.Skr;
        fp.Spbmbbh = "12.0";//商品编码版本号(20字节)(必输项)
        fp.Hsbz = "0";//含税标志 0:不含税税率,1:含税税率,2:差额税;中外合作油气田(原海洋石油)5%税率、1.5%税率为1,差额税为2,其他为0;
        fp.Sgbz = "0";
        fp.Spxx = new List<Sph>();

        int i = 1;
        foreach (var jsDetail in jsGroup)
        {
            var sph = new Sph();
            sph.Xh = i.ToString();         //序号
            sph.Spmc = jsDetail.Spmc; //商品名称,金额为负数时此行是折扣行,折扣行的商品名称应与上一行的商品名称一致(100字节)
            sph.Ggxh = jsDetail.Ggxh;  //规格型号(40字节)
            sph.Jldw = jsDetail.Jldw;   //计量单位(32字节)
            sph.Spbm = SubStr(jsDetail.Spbm, 19);   //商品编码(19字节)(必输项)
            sph.Qyspbm = string.Empty;  //企业商品编码(20字节)
            sph.Syyhzcbz = "0";         //是否使用优惠政策标识0:不使用,1:使用(1字节)
            sph.Lslbz = string.Empty;   //零税率标识   空:非零税率,0:出口退税,1:免税,2:不征收,3普通零税率(1字节)
            sph.Yhzcsm = string.Empty;  //优惠政策说明(50字节)
            sph.Sl = jsDetail.Sl;	    //数量
            sph.Je = jsDetail.Je;       //金额,当金额为负数时为折扣行
            sph.Dj = (double.Parse(sph.Je) / double.Parse(sph.Sl)).ToString(); //单价(中外合作油气田(原海洋石油)5%税率,单价为含税单价)
            sph.Slv = jsDetail.Slv;		//税率
            sph.Kce = "0";     //扣除额,用于差额税计算
            fp.Spxx.Add(sph);
            i++;
        }
        kp.Fpxx.Fpsj.Add(fp);
    }

    return kp;
}
public void ResponseXml(Kp kp)
{
    var dj = kp.Fpxx.Fpsj[0].Djh;
    if (kp.Fpxx.Fpsj.Count > 1)
    {
        dj += "-" + kp.Fpxx.Fpsj.Last().Djh;
    }

    StringGBKWriter sw = new StringGBKWriter();
    XmlSerializer xz = new XmlSerializer(kp.GetType());
    xz.Serialize(sw, kp);

    HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + dj + ".xml");
    HttpContext.Current.Response.Charset = "GBK";
    HttpContext.Current.Response.ContentEncoding = Encoding.GetEncoding("GBK");
    HttpContext.Current.Response.ContentType = "text";//image/JPEG;text/HTML;image/GIF;vnd.ms-excel/msword 

    var nsw = sw.ToString().Replace("<?xml version=\"1.0\" encoding=\"gb2312\"?>", "<?xml version=\"1.0\" encoding=\"GBK\" ?>")
            .Replace("<Kp xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">", "<Kp>");
    HttpContext.Current.Response.Write(nsw);
    HttpContext.Current.Response.End();
}

 

金税接口参考文件:

增值税发票税控开票软件数据接口规范.doc (114.00 kb)

nginx在云智系统和云智博客使用

云智系统和博客使用的是阿里云的服务,目前购买了ECS和RDS等服务.

1.ssl证书加载在nginx上,使用的是GeoTrust通配符域名专业版OV SSL证书类型,可对所有的二级域名(*.ciemis.com)域名提供服务

2.启用了http2

3.云智系统(www.ciemis.com)可以使用http和https两种方式访问.云智博客(blog.ciemis.com)只支持https访问,http访问是会自动通过301跳转到https.当然也可以通过javascript进行跳转,代码如下:

var ishttps = 'https:' == document.location.protocol ? true : false;
if (!ishttps) {
    window.location.href = "https:" + window.location.href.substring(window.location.protocol.length);
}

4.为了将多个ciemis.com的二级域名绑定到同一台服务器上,我使用了nginx作为反向代理.

www.ciemis.com在IIS上使用的是3017端口,blog.ciemis.com在IIS上使用的是3000端口, 然后在ngnix上配置了反向代理.

当然直接在IIS上绑定主机头也是可行的.

nginx的配置文件节选如下:

#云智
server {
    #监听端口
    listen       80;
    #自己指定要跳转的域名
    server_name  www.ciemis.com;
		        
    #反向代理配置
    location / {
        proxy_pass     http://localhost:3017;
        proxy_set_header   X-Real-IP $remote_addr;
    }
}

server {
    #监听端口
    listen       443 ssl http2;
    #自己指定要跳转的域名
    server_name  www.ciemis.com;
		
    ssl                  on; 
    ssl_certificate   cert/214xxxxxx0803.pem;
    ssl_certificate_key  cert/214xxxxxx0803.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
        
    #反向代理配置
    location / {
        proxy_pass     http://localhost:3017;
        proxy_set_header   X-Real-IP $remote_addr;
    }
}
	
#云智blog
server {
    #监听端口
    listen       80;
    #自己指定要跳转的域名
    server_name  blog.ciemis.com;
		        
    #转向https
    return  301 https://$host;
}
	
server {
    #监听端口
    listen       443 ssl http2;
    #自己指定要跳转的域名
    server_name  blog.ciemis.com;
		
    ssl                  on; 
    ssl_certificate   cert/214xxxxxx0803.pem;
    ssl_certificate_key  cert/214xxxxxx0803.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
        
    #反向代理配置
    location / {
        proxy_pass     http://localhost:3000;
        proxy_set_header   X-Real-IP $remote_addr;
    }
}

附nginx的启动,重启,关闭命令

start nginx #启动nginx

nginx -s reload  #修改配置后重新加载生效
nginx -s reopen  #重新打开日志文件
nginx -t -c /path/to/nginx.conf  #测试nginx配置文件是否正确

#关闭nginx:
nginx -s stop  #快速停止nginx
         quit  #完整有序的停止nginx

 

NPOI在云智系统中的使用

在云智系统中,有许多的数据需要导入到excel,使用微软的office对于web来说要求对服务器的权限过高,所以我使用的第三方的开源软件NPOI.

下面的代码示例就是直接将DataTable转为Excel.表头通过titleArr进行定义.

/// <summary>  
/// 导出Excel  
/// </summary>  
/// <param name="Dt">数据源</param>  
/// <param name="ExcleName">导入文件名称</param>  
/// <param name="SheetName">工作薄名称</param>  
/// <param name="titleArr">标题栏</param>  
/// <param name="clumnArr">栏位名</param>  
public static void ResponseDataSetToExcel(DataTable Dt, string ExcleName, string SheetName, string[] titleArr, string[] clumnArr)
{
    HSSFWorkbook hssfworkbook = new HSSFWorkbook();

    DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation();
    dsi.Company = "Ciemis";
    hssfworkbook.DocumentSummaryInformation = dsi;

    //create a entry of SummaryInformation  
    SummaryInformation si = PropertySetFactory.CreateSummaryInformation();
    si.Subject = " Export  Excel";
    hssfworkbook.SummaryInformation = si;

    HSSFSheet excelSheet = (HSSFSheet)hssfworkbook.CreateSheet(SheetName);
    int rowCount = 0;
    HSSFRow newRow = (HSSFRow)excelSheet.CreateRow(0);
    rowCount++;
    //循环写出列头           
    for (int i = 0; i < titleArr.Length; i++)
    {
        HSSFCell newCell = (HSSFCell)newRow.CreateCell(i);
        newCell.SetCellValue(titleArr[i]);
    }
    for (int i = 0; i < Dt.Rows.Count; i++)
    {
        rowCount++;
        HSSFRow newRowData = (HSSFRow)excelSheet.CreateRow(rowCount);
        DataRow dr = Dt.Rows[i];
        for (int j = 0; j < clumnArr.Length; j++)
        {
            HSSFCell newCell = (HSSFCell)newRow.CreateCell(rowCount);
            newCell.SetCellValue(dr[titleArr[j]].ToString());
        }
    }

    HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
    //避免乱码System.Text.Encoding.UTF8
    HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(ExcleName, System.Text.Encoding.UTF8));
    HttpContext.Current.Response.Clear();

    MemoryStream file = new MemoryStream();
    hssfworkbook.Write(file);

    HttpContext.Current.Response.BinaryWrite(file.GetBuffer());
    HttpContext.Current.Response.Flush();
    HttpContext.Current.Response.End();
}

要导出一个DataSet,里面的多个DataTable对应Excel的多个Sheet;

且自动根据数据类型设置Excel的单元格格式.

/// <summary>
/// 导出Excel  
/// </summary>
/// <param name="sourceDs"></param>
/// <param name="fileName">导出的文件名</param>
/// <param name="sheetName">导出���表名,多个表请以逗号(,)分割</param>
public static void ResponseDataSetToExcel(DataSet sourceDs, string fileName, string sheetName = null)
{
    fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8).ToString();

    HSSFWorkbook workbook = new HSSFWorkbook();
    MemoryStream ms = new MemoryStream();
    string[] sheetNames = (sheetName ?? string.Empty).Split(',');
    int length = sourceDs.Tables.Count;
    for (int i = 0; i < length; i++)
    {
        var _sheetName = sheetNames.Length > i ? sheetNames[i] : string.Format("Sheet{0}", i);
        var sheet = workbook.CreateSheet(_sheetName);
        sheet.CreateFreezePane(0, 1, 0, 1);
        //headStyle
        var headStyle = workbook.CreateCellStyle();
        IFont font = workbook.CreateFont();
        font.Boldweight = (short)FontBoldWeight.Bold;
        font.FontHeightInPoints = (short)11;
        font.Color = HSSFColor.Black.Index;
        headStyle.FillBackgroundColor = HSSFColor.Black.Index;
        //headStyle.FillPattern = FillPattern.SolidForeground;
        headStyle.SetFont(font);
        //cellStyleDet
        var cellStyleDet = workbook.CreateCellStyle();
        IFont font1 = workbook.CreateFont();
        font.FontHeightInPoints = (short)10;
        cellStyleDet.SetFont(font1);

        var headerRow = sheet.CreateRow(0);
        // handling header.
        foreach (DataColumn column in sourceDs.Tables[i].Columns)
        {
            var headCell = headerRow.CreateCell(column.Ordinal);
            headCell.SetCellValue(column.ColumnName);
            headCell.CellStyle = headStyle;
        }
        // handling value.
        int rowIndex = 1;
        foreach (DataRow row in sourceDs.Tables[i].Rows)
        {
            var dataRow = sheet.CreateRow(rowIndex);
            foreach (DataColumn column in sourceDs.Tables[i].Columns)
            {
                var detCell = dataRow.CreateCell(column.Ordinal);
                var cellValue = row[column].ToString();
                var type = column.DataType.ToString().ToLower();
                if (row[column] != DBNull.Value)
                {
                    if (type.Contains("decimal") || type.Contains("double") || type.Contains("int"))
                    {
                        detCell.SetCellValue(Convert.ToDouble(row[column]));
                    }
                    else if (type.Contains("datetime"))
                    {
                        detCell.SetCellValue(((DateTime)row[column]).ToString("yyyy-MM-dd HH:mm:ss"));
                    }
                    else
                    {
                        detCell.SetCellValue(row[column].ToString());
                    }
                }
                detCell.CellStyle = cellStyleDet;
            }
            rowIndex++;
        }
    }
    workbook.Write(ms);

    HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName);
    HttpContext.Current.Response.BinaryWrite(ms.GetBuffer());
    HttpContext.Current.Response.Flush();
    HttpContext.Current.Response.End();

    ms.Flush();
    ms.Position = 0;
    ms.Close();
    workbook = null;
    ms = null;
}

如果想对excel进行只读处理,不许对导出的数据进行修改,只需要加入一行代码:

sheet.ProtectSheet("password");