• ASP.NET MVC实现Excel文件的上传下载


    在应用系统开发当中,文件的上传和下载是非常普遍的需求。在基于.NET的C/S架构的项目开发当中,有多种方案可以实现文件的上传和下载(httpwebrequest、webclient等),而且多采用异步(xxxxAsync或async/await等)的方式实现。而在基于.NET的B/S架构的项目开发当中,虽然webform提供了上传控件(HttpPostFile),但用户体验并不好(页面刷新,如果上传大文件则卡死,即不支持分块上传),虽然有基于Flash的上传文件的解决方案,但Flash已经过时(安全性差)。因此我们一般采用基于h5+js的上传文件插件的解决方案。本文介绍的是使用WebUploader控件结合ASP.NET MVC实现文件的上传、下载以及上传成功后将Excel数据保存到SQL Server数据库中的功能。

    关于WebUploader的介绍,读者可以去查看官方网页 http://fex.baidu.com/webuploader/,跟ECharts一样,这也是百度开发的基于h5+js的开源上传文件插件。官网上面也有详细的使用介绍,基本上是介绍了js前端的配置和关键代码,但后端代码并没有提供,需要读者自行实现。

    在ASP.NET MVC4中使用WebUploader只需要导入开发包中的js和css文件就可以了。比如:

     <link href="@Url.Content("~/Scripts/webuploader/webuploader.css")" rel="stylesheet" type="text/css" />
     <link href="@Url.Content("~/Scripts/webuploader/bootstrap.css")" rel="stylesheet" type="text/css" />
     <link href="@Url.Content("~/Scripts/webuploader/style.css")" rel="stylesheet" type="text/css" />
     <script src="@Url.Content("~/Scripts/webuploader/jquery-1.10.2.min.js")" type="text/javascript"></script>
     <script src="@Url.Content("~/Scripts/webuploader/bootstrap.js")" type="text/javascript"></script>
     <script src="@Url.Content("~/Scripts/webuploader/webuploader.js")" type="text/javascript"></script>

    然后是Html部分:

     <div id="uploader">
         <div id="thelist" class="uploader-list"></div>
         <div class="btns">
             <div id="picker">选择文件</div>
             <input id="ctlBtn" type="button" value="开始上传" class="btn btn-default" />
             @Html.ActionLink("下载Excel", "DownLoad", null, new { @class = "btn btn-default" })
         </div>
     </div>

    这里面的id和class都是webuploader默认为我们提供的,后面的btn-default则是bootstrap为我们提供的。

    关键的就是js部分代码:

    <script type="text/javascript">
         var applicationPath = window.applicationPath === "" ? "" : window.applicationPath || "../../";
         var GUID = WebUploader.Base.guid();
         $(function () {
             var $ = jQuery;
             var $list = $('#thelist');
             var uploader = WebUploader.create({
                 auto: false, // 是否自动上传
                 swf: applicationPath + '../Scripts/webuploader/Uploader.swf',
    
                 //server: applicationPath + 'DAManage/Upload',
                 server: '@Url.Action("Upload", "Test")',
                 pick: '#picker',
                 accept: {
                     title: 'Excels',
                     extensions: 'xls,xlsx',
                     mimeTypes: 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
                 },
                 chunked: true, //分片上传
                 chunkSize: 2048000, //每一片的大小
                 formData: {
                     guid: GUID
                 },
                 resize: false //不压缩image
             });
    
             //添加进上传文件队列
             uploader.on('fileQueued', function (file) {
                 $list.append('<div id="' + file.id + '" class="item">' +
                 '<h4 class="info">' + file.name + '</h4>' +
                 '<p class="state">等待上传...</p>' +
                '</div>');
             });
    
             //开始上传
             $("#ctlBtn").click(function () {
                 uploader.upload();
             });
    
             //上传进度
             uploader.on('uploadProgress', function (file, percentage) {
                 var $li = $('#' + file.id),
                 $percent = $li.find('.progress .progress-bar');
    
                 // 避免重复创建
                 if (!$percent.length) {
                     $percent = $('<div class="progress progress-striped active">' +
                   '<div class="progress-bar" role="progressbar" style=" 0%">' +
                   '</div>' +
                   '</div>').appendTo($li).find('.progress-bar');
                 }
                 $li.find('p.state').text('上传中');
                 $percent.css('width', percentage * 100 + '%');
             });
    
             //上传成功
             uploader.on('uploadSuccess', function (file, response) {
                 $('#' + file.id).find('p.state').text('已上传');
                 $.post('@Url.Action("Merge", "Test")', { guid: GUID, fileName: file.name }, function (data) {
                     $("#uploader .state").html("上传成功...");
                     uploader.removeFile(file);
                 });
             });
    
             // 上传失败
             uploader.on('uploadError', function (file) {
                 $('#' + file.id).find('p.state').text('上传出错');
             });
    
             //上传完成后
             uploader.on('uploadComplete', function (file) {
                 $('#' + file.id).find('.progress').fadeOut();
             });
    
             //上传完毕
             uploader.on("uploadFinished", function () {
                 uploader.reset();
             });
         });
     </script>

    上面我给出了基本的注释,想要获取参数的详细定义和说明,请参考:http://fex.baidu.com/webuploader/doc/index.html

    后端控制器部分代码,主要是上面js中所指向的两个Action,分别为Upload和Merge。

    Upload部分代码:

    /// <summary>
    /// 上传Excel
    /// </summary>
    /// <returns>1表示失败,0表示成功</returns>
    [HttpPost]
    public ActionResult Upload()
    {
        var fileName = Request["name"];
        var fileRelName = fileName.Substring(0, fileName.LastIndexOf('.'));
        int index = Convert.ToInt32(Request["chunk"]);
        var dir = Server.MapPath("~/Upload");
        dir = Path.Combine(dir, fileRelName);
        if (!System.IO.Directory.Exists(dir))
            System.IO.Directory.CreateDirectory(dir);
    
        try
        {
            string filePath = Path.Combine(dir, index.ToString());
            var data = Request.Files["file"];
            data.SaveAs(filePath);
        }
        catch (Exception)
        {
            return Json(new { error = 1 });
        }
        return Json(new { erron = 0 });
    }

    Merge部分代码:

    /// <summary>
    /// 合并Excel成功后,将其数据导入数据库
    /// </summary>
    /// <returns>1表示失败,0表示成功</returns>
    public ActionResult Merge()
    {
        var uploadDir = Server.MapPath("~/Upload");
        var fileName = Request["fileName"];
        var fileRelName = fileName.Substring(0, fileName.LastIndexOf('.'));
        var dir = Path.Combine(uploadDir, fileRelName);//临时文件夹          
        var files = System.IO.Directory.GetFiles(dir);
        var finalPath = Path.Combine(uploadDir, fileName);
        var fs = new FileStream(finalPath, FileMode.Create);
        foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))//排一下序,保证从0-N块写入
        {
            var bytes = System.IO.File.ReadAllBytes(part);
            fs.Write(bytes, 0, bytes.Length);
            System.IO.File.Delete(part);//删除分块
        }
        fs.Flush();
        fs.Close();
        System.IO.Directory.Delete(dir);//删除文件夹
    
        try
        {
            //读取上传的Excel并保存到数据库
            DbHelper.Excel2DB(finalPath, "Sheet1");
        }
        catch (Exception)
        {
            return Json(new { error = 1 });
        }
        return Json(new { error = 0 });
    }

    WebUploader是基于分块上传(这个设计主要针对大文件的上传)的,所以后端的处理也是分块合并的。Merge中的Excel2DB方法是将上传到服务器的Excel文件中的数据保存到数据库的方法,其中涉及Excel文件内容的读取(NPOI,支持xls和xlsx类型)和EF(5.0)实现数据的保存(保存到SQLServer)。具体的代码可以参考本篇博客最后的示例代码下载。

    而关于文件的下载,其实ASP.NET MVC已经提供了FileResult类型,只需要返回File对象就可以了,具体的Action代码如下:

     /// <summary>
     /// 下载excel
     /// </summary>
     /// <returns></returns>
     public FileResult DownLoad()
     {
         var path = Server.MapPath("~/Upload/");
         var file = System.IO.Directory.GetFiles(path).OrderByDescending(t => new FileInfo(t).CreationTime).FirstOrDefault();
         return File(file, "application/vnd.ms-excel", new FileInfo(file).Name);
     }

    File对应的第二个参数是Content-Type,由于这里要下载Excel,所以用了application/vnd.ms-excel。关于如何确定各种文件类型的Content-Type可以查看这个网址里的内容:http://tool.oschina.net/commons

    对应的前端代码上面已经贴过了,代码如下:

    @Html.ActionLink("下载Excel", "DownLoad", null, new { @class = "btn btn-default" })

    代码下载地址:https://pan.baidu.com/s/1pMbK0e3

  • 相关阅读:
    阻止默认时间
    键盘事件
    提示框跟随鼠标移动
    世纪经典案例之万年历
    事件冒泡
    事件对象
    java 面向对象(三十八):反射(二) Class类的理解与获取Class的实例
    java 面向对象(三十九):反射(三)了解ClassLoader
    java 面向对象(四十一):反射(五)反射应用二:获取运行时类的完整结构
    java 面向对象(四十):反射(四)反射应用一:创建运行时类的对象
  • 原文地址:https://www.cnblogs.com/guwei4037/p/8459058.html
Copyright © 2020-2023  润新知