NET MVC 和WebUploader上传大文件

  1. 大文件上传部分:重磅功能:大文件“秒传”;在文件上传部分已有功能的基础上实现了按10MB分为多个块,异步上传,服务端合并,MD5验证;

  2. 图片上传部分:在文件上传部分已有功能的基础上实现了上传前缩略图预览,前台js文件后缀验证,后台代码文件后缀验证和文件类型验证(就算修改后缀名也无法成功上传),支持图片上传前压缩;

BigFileUpload文件夹下Index.cshtml

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>大文件上传</title>
    <!--支持IE9+ chrome fireFox-->
    <script src="~/Scripts/jquery-2.1.4.min.js"></script>
    <link href="~/Content/webuploader.css" rel="stylesheet"/>
    <script src="~/Scripts/webuploader.nolog.js"></script>
    <link href="~/Content/bootstrap.min.css" rel="stylesheet"/>
    <script src="~/Scripts/bootstrap.min.js"></script>


    <script type="text/javascript">
        $(function() {
            $list = $('#fileList');
            var uploader = WebUploader.create({


                //设置选完文件后是否自动上传
                auto: false,


                //swf文件路径
                //swf: BASE_URL + '~/FileUpload/Uploader.swf',
                swf: '../FileUpload/Uploader.swf',

                // 文件接收服务端。
                server: '/BigFileUpload/BigFileUp',

                // 选择文件的按钮。可选。
                // 内部根据当前运行是创建,可能是input元素,也可能是flash.
                pick: '#picker',

                chunked: true, //开启分块上传
                chunkSize: 10 * 1024 * 1024,
                chunkRetry: 3, //网络问题上传失败后重试次数
                threads: 5, //上传并发数
                //formData: { guid: WebUploader.guid() },  //一个文件有一个guid,在服务器端合并成一个文件  这里有个问题,多个文件或者上传一个文件成功后不刷新直接添加文件上传生成的guid不变!!!   暂时只能传一个大文件(已解决)
                //fileNumLimit :1,
                fileSizeLimit: 2000 * 1024 * 1024, //最大2GB
                fileSingleSizeLImit: 2000 * 1024 * 1024,


                resize: false //不压缩

                //选择文件类型
                //accept: {
                //    title: 'Images',
                //    extensions: 'gif,jpg,jpeg,bmp,png',
                //    mimeTypes: 'image/*'
                //}
            });


            // 当有文件被添加进队列的时候
            uploader.on('fileQueued',
                function(file) {
                    $list.append('<div id="' +
                        file.id +
                        '" class="item">' +
                        '<h4 class="info">' +
                        file.name +
                        '<button type="button" fileId="' +
                        file.id +
                        '" class="btn btn-danger btn-delete"><span class="glyphicon glyphicon-trash"></span></button></h4>' +
                        '<p class="state">等待上传...</p>' +
                        '</div>'); //id="' + file.id + 'btn"
                    //删除要上传的文件
                    //每次添加文件都给btn-delete绑定删除方法
                    $(".btn-delete").click(function() {
                        //console.log($(this).attr("fileId"));//拿到文件id
                        uploader.removeFile(uploader.getFile($(this).attr("fileId"), true));
                        $(this).parent().parent().fadeOut(); //视觉上消失了
                        $(this).parent().parent().remove(); //DOM上删除了
                    });

                    uploader.options.formData.guid = WebUploader.guid(); //每个文件都附带一个guid,以在服务端确定哪些文件块本来是一个

                    uploader.md5File(file)
                        .then(function(fileMd5) { // 完成
                            //var end = +new Date();
                            // console.log("before-send-file  preupload: file.size="+file.size+" file.md5="+fileMd5);
                            //insertLog("<br>" + moment().format("YYYY-MM-DD HH:mm:ss") + " before-send-file  preupload:计算文件(" + file.name + ")MD5完成. 耗时  " + (end - start) + '毫秒  fileMd5: ' + fileMd5);
                            file.wholeMd5 = fileMd5; //获取到了md5
                            uploader.options.formData.md5value = file.wholeMd5; //每个文件都附带一个md5,便于实现秒传
                            $.ajax({ //向服务端发送请求
                                cache: false,
                                type: "post",
                                dataType: "json",
                                url: "/BigFileUpload/IsMD5Exist", //baseUrl +
                                data: {
                                    fileMd5: fileMd5,
                                    fileName: file.name,
                                    fileID: file.id,
                                    //isShared: $("#isShared").val()
                                },
                                success: function(result) {
                                    console.log(result);
                                    if (result == "this file is exist") {
                                        console.log("服务器上已经有同样的文件了,开始秒传!");

                                        uploader.removeFile(file, true);

                                        $('#' + file.id).find('p.state').text('已上传');
                                        $('#' + file.id).find(".progress").find(".progress-bar")
                                            .attr("class", "progress-bar progress-bar-success");
                                        $('#' + file.id).find(".info").find('.btn').fadeOut('slow'); //上传完后删除"删除"按钮
                                    } else {
                                        console.log("服务器上没有同样的文件,秒传失败!");
                                    }


                                    //$('#uploadBtn').attr("disabled", false);
                                    //me.options.formData.fileMd5 = fileMd5;
                                    //me.options.formData.isShared = $("#isShared").val();
                                    //me.options.formData.fileType = $("#fileType").val();
                                    //if (result.result) {//文件存在
                                    //    insertLog("<br>" + moment().format("YYYY-MM-DD HH:mm:ss") + " before-send-file  preupload:文件 " + file.name + " 已经存在,跳过上传   fileMd5:" + fileMd5);
                                    //    $MD5Percent.hide();
                                    //    var $li = $('#' + file.id),
                                    //    $percent = $li.find('.progress  .progress-bar-success');
                                    //    $li.find('span.state').text('文件重复,已跳过');
                                    //    $percent.css('width', 100 + '%');
                                    //    owner.skipFile(file);
                                    //} else {//文件不存在
                                    //    file.wholeMd5 = fileMd5;
                                    //    file.chunkMd5s = result.chunkMd5s;  //如果后台已经有该文件的分片记录
                                    //}

                                     me.data.chunksMd5 = "chunksMd5";
                                    //$('#' + file.id + ' .cancleBtn').removeClass("btn-info");
                                    //$('#' + file.id + ' .cancleBtn').attr("disabled", true);
                                    //deferred.resolve(true);
                                     return deferred.reject();
                                }
                            });
                        });

                });

            // 文件上传过程中创建进度条实时显示。
            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="width: 0%">' +
                            '</div>' +
                            '</div>').appendTo($li).find('.progress-bar');
                    }

                    $li.find('p.state').text('上传中');

                    $percent.css('width', percentage * 100 + '%');
                });
            给每个文件一个唯一的guid值
            //uploader.on('uploadBeforeSend', function (block, data) {
            //    // block为分块数据。

            //    // file为分块对应的file对象。
            //    //var file = block.file;


            //    // 修改data可以控制发送哪些携带数据。
            //    //data.uid = 123;

            //    // 将存在file对象中的md5数据携带发送过去。
            //    // data.fileMd5 = file.md5;

            //    // 删除其他数据
            //    // delete data.key;
            //});

            uploader.on('uploadSuccess',
                function(file) {
                    $('#' + file.id).find('p.state').text('已上传');
                    $('#' + file.id).find(".progress").find(".progress-bar")
                        .attr("class", "progress-bar progress-bar-success");
                    $('#' + file.id).find(".info").find('.btn').fadeOut('slow'); //上传完后删除"删除"按钮
                });

            uploader.on('uploadError',
                function(file) {
                    $('#' + file.id).find('p.state').text('上传出错');
                    //上传出错后进度条爆红
                    $('#' + file.id).find(".progress").find(".progress-bar")
                        .attr("class", "progress-bar progress-bar-danger");
                    //添加重试按钮
                    //为了防止重复添加重试按钮,做一个判断
                    //var retrybutton = $('#' + file.id).find(".btn-retry");
                    //$('#' + file.id)
                    if ($('#' + file.id).find(".btn-retry").length < 1) {
                        var btn = $('<button type="button" fileid="' +
                            file.id +
                            '" class="btn btn-success btn-retry"><span class="glyphicon glyphicon-refresh"></span></button>');
                        $('#' + file.id).find(".info").append(btn); //.find(".btn-danger")
                    }


                    $(".btn-retry").click(function() {
                        //console.log($(this).attr("fileId"));//拿到文件id
                        uploader.retry(uploader.getFile($(this).attr("fileId")));

                    });
                });

            uploader.on('uploadComplete',
                function(file) { //上传完成后回调
                    //$('#' + file.id).find('.progress').fadeOut();//上传完删除进度条
                    //$('#' + file.id + 'btn').fadeOut('slow')//上传完后删除"删除"按钮
                });

            uploader.on('uploadFinished',
                function() {
                    //上传完后的回调方法
                    //alert("所有文件上传完毕");
                    //提交表单
                });

            $("#UploadBtn").click(function() {
                uploader.upload(); //上传
            });

            $("#StopBtn").click(function() {
                //uploader.upload();//上传

                uploader.stop(true); //暂停上传有问题,这个变成了终止上传,开始之后就是完全重新上传了

            });


            uploader.on('uploadAccept',
                function(file, response) {
                    //if (uploader.errorCode) {
                    //    // 通过return false来告诉组件,此文件上传有错。
                    //    return false;
                    //}
                    if (response._raw == '{"error":true}') {
                        return false;
                    }

                });


            // 扩展md5逻辑
            //var uploader = WebUploader.Uploader;

            /**
             * method:before-send-file
             * 在文件发送之前request,此时还没有分片(如果配置了分片的话),可以用来做文件整体md5验证。
             * para:file: File对象
             */
            //uploader.register({
            //    'before-send-file': 'preupload'
            //}, {
            //    preupload: function (file) {
            //        $('#UploadBtn').attr("disabled", true);
            //        var me = this,
            //        owner = this.owner,
            //        server = me.options.server,
            //        deferred = WebUploader.Deferred(),
            //        blob = file.source.getSource();


            //        //var fileMd5 = file.wholeMd5;
            //        var start = +new Date();
            //        var $li = $('#' + file.id),
            //        $MD5Percent = $li.find('.progress  .progress-bar-info');
            //        $li.find('span.state').text('计算MD5');
            //        insertLog("<br>" + moment().format("YYYY-MM-DD HH:mm:ss") + " before-send-file  preupload:开始计算文件(" + file.name + ")MD5. ");
            //        owner.md5File(file)
            //        .progress(function (percentage) {   // 及时显示进度
            //            var percent = parseInt(percentage * 100) + '%';
            //            $MD5Percent.css('width', percent);
            //            $MD5Percent.html(percent);
            //            //console.log('Percentage:', percent);
            //        })
            //        .then(function (fileMd5) {   // 完成
            //            var end = +new Date();
            //            // console.log("before-send-file  preupload: file.size="+file.size+" file.md5="+fileMd5);
            //            insertLog("<br>" + moment().format("YYYY-MM-DD HH:mm:ss") + " before-send-file  preupload:计算文件(" + file.name + ")MD5完成. 耗时  " + (end - start) + '毫秒  fileMd5: ' + fileMd5);
            //            file.wholeMd5 = fileMd5;

            //            $.ajax({
            //                cache: false,
            //                type: "post",
            //                dataType: "json",
            //                url: baseUrl + "/fileUpload/existsMd5",
            //                data: {
            //                    fileMd5: fileMd5,
            //                    fileName: file.name,
            //                    isShared: $("#isShared").val()
            //                },
            //                success: function (result) {

            //                    $('#uploadBtn').attr("disabled", false);
            //                    me.options.formData.fileMd5 = fileMd5;
            //                    me.options.formData.isShared = $("#isShared").val();
            //                    me.options.formData.fileType = $("#fileType").val();
            //                    if (result.result) {//文件存在
            //                        insertLog("<br>" + moment().format("YYYY-MM-DD HH:mm:ss") + " before-send-file  preupload:文件 " + file.name + " 已经存在,跳过上传   fileMd5:" + fileMd5);
            //                        $MD5Percent.hide();
            //                        var $li = $('#' + file.id),
            //                        $percent = $li.find('.progress  .progress-bar-success');
            //                        $li.find('span.state').text('文件重复,已跳过');
            //                        $percent.css('width', 100 + '%');
            //                        owner.skipFile(file);
            //                    } else {//文件不存在
            //                        file.wholeMd5 = fileMd5;
            //                        file.chunkMd5s = result.chunkMd5s;  //如果后台已经有该文件的分片记录
            //                    }

            //                    // me.data.chunksMd5 = "chunksMd5";
            //                    $('#' + file.id + ' .cancleBtn').removeClass("btn-info");
            //                    $('#' + file.id + ' .cancleBtn').attr("disabled", true);
            //                    deferred.resolve(true);
            //                    // return deferred.reject();
            //                }
            //            });
            //        });

            //        return deferred.promise();
            //    }
            //});


        });


    </script>

</head>
<body>
<div class="container" style="margin-top: 20px">
    <div class="alert alert-info">可以一次上传多个大文件</div>
</div>
<div class="container" style="margin-top: 50px">
    <div id="uploader" class="container">
        <div class="container">
            <div id="fileList" class="uploader-list"></div> <!--存放文件的容器-->
        </div>
        <div class="btns container">
            <div id="picker" class="webuploader-container" style="float: left; margin-right: 10px">
                <div>
                    选择文件
                    <input type="file" name="file" class="webuploader-element-invisible" multiple="multiple">
                </div>
            </div>

            <div id="UploadBtn" class="webuploader-pick" style="float: left; margin-right: 10px">开始上传</div>
            <div id="StopBtn" class="webuploader-pick" style="float: left; margin-right: 10px">暂停上传</div>
        </div>
    </div>
</div>

</body>
</html>

BigFileUploadController.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using FileUpload.Models;

namespace FileUpload.Controllers
{
    public class BigFileUploadController : FileBaseController
    {
        // GET: BigFileUpload
        public ActionResult Index()
        {
            return View();
        }

        // GET: FileUpload
        //解决文件上传最大4M的显示可在web.config中设置,当前设置,最大上传大小2GB,最大上传时间一小时
        public ActionResult BigFileUp(string guid, string md5value, string chunks, string chunk, string id, string name,
            string type, string lastModifiedDate, int size, HttpPostedFileBase file)
        {
            //全程没有做文件后缀或者类型验证,需要的应该在开始就做验证
            //object lockObj = null;

            if (Request.Files.Count == 0)
            {
                return Json(new {error = true});
            }


            string ex = Path.GetExtension(file.FileName);
            string fileFullName = String.Empty;
            string localPath = String.Empty;
            try
            {
                localPath = Path.Combine(HttpRuntime.AppDomainAppPath, "Upload");
            }
            catch (Exception)
            {
                localPath = "D:\\代码\\ASP.NET\\FileUpload\\FileUpload\\Upload"; //单元测试用
            }


            //取得分块和信号信息
            int fenkuai = 0;
            int xuhao = 0;
            if (chunks != null && chunk != null)
            {
                fenkuai = Convert.ToInt32(chunks);
                xuhao = Convert.ToInt32(chunk);
                //isOk = fenkuai;//每次写入文件后-1,到0了就可以合并了(已放弃)
            }
            else
            {
                //文件没有分块直接保存
                fileFullName = Guid.NewGuid().ToString("N") + ex;
                //file.SaveAs(Path.Combine(HttpRuntime.AppDomainAppPath + "\\Upload", fileFullName));

                if (!SaveFile(localPath, fileFullName, file))
                {
                    return Json(new {error = true});
                }
                else
                {
                }

                #region 保存文件md5到数据库

                FileModel model = new FileModel();
                FileUpload.Models.FileInfo upfile = new FileUpload.Models.FileInfo();
                upfile.FileMD5 = md5value;
                upfile.FileName = fileFullName;
                model.FileInfoSet.Add(upfile);
                model.SaveChanges();

                #endregion

                return Json(new
                {
                    jsonrpc = "2.0",
                    id = id,
                    filePath = "/Upload/" + fileFullName
                });
            }


            string tempPath = "Upload";
            if (guid != null)
            {
                tempPath = tempPath + "\\" + guid.ToString();
            }

            //string localPath = Path.Combine(HttpRuntime.AppDomainAppPath, tempPath);//保存的路径
            tempPath = Path.Combine(HttpRuntime.AppDomainAppPath, tempPath); //保存的路径


            //没有做文件类型验证
            //fileFullName = Guid.NewGuid().ToString("N") + ex;
            fileFullName = "temp" + xuhao.ToString() + ex;
            //应该先把分块的文件存到以guid命名的临时文件夹下,待文件夹下的文件数目达到分块数目后拼接成一个文件,并删除临时文件
            if (!SaveFile(tempPath, fileFullName, file))
            {
                return Json(new {error = true});
            }
            else
            {
                //分块文件保存成功后要判断是否合并文件
            }


            #region MyRegion

            //if (!System.IO.Directory.Exists(tempPath))
            //{
            //    System.IO.Directory.CreateDirectory(tempPath);//不存在该文件夹就新建一个
            //}
            //try
            //{
            //    //if (isOk == 1)
            //    //{

            //    //}
            //    file.SaveAs(Path.Combine(tempPath, fileFullName));
            //    //isOk = isOk - 1;

            //}
            //catch (Exception)
            //{
            //    //异常处理   Log4Net 
            //    //return HttpNotFound();
            //    return Json(new { error = true });//新的错误返回方式,更加轻量!
            //} 

            #endregion


            //finally
            if (xuhao == 0) //第一个分块负责上传的进程留下来合并文件
            {
                //此处有多线程问题,所以可能出现合并出多个文件的情况,而且下面只判断了文件数目,可能文件还没写入完成!(已解决,看上面)

                //待文件夹下的文件数目达到分块数目后拼接成一个文件,并删除临时文件
                //fileFullName文件夹
                int count = 0;
                DirectoryInfo TempFolder = new DirectoryInfo(tempPath);
                foreach (var tempFile in TempFolder.GetFiles())
                {
                    count = count + 1;
                }

                if (count == fenkuai)
                {
                    //while (isOk != 0)
                    //{
                    //    Thread.Sleep(1000);
                    //}
                    //lock (lockObject)
                    //{

                    //}
                    //达到合并的要求了
                    //序号从0开始
                    string path = Path.Combine(HttpRuntime.AppDomainAppPath, "Upload"); //保存的路径
                    //string path = Path.Combine(HttpRuntime.AppDomainAppPath, "Upload\\"+guid);//测试:保存的路径

                    string filefullname = Guid.NewGuid().ToString() + ex;
                    //下面应该用using块实现
                    FileStream fa = new FileStream(path + "\\" + filefullname, FileMode.Append, FileAccess.Write);
                    for (int i = 0; i < count; i++)
                    {
                        byte[] buffer = new byte[11 * 1024 * 1024];
                        //FileStream fileTemp = new FileStream(tempPath + "\\temp"+i+ex, FileMode.Open, FileAccess.Read,FileShare.ReadWrite);

                        //解决了文件占用问题
                        int tryTimes = 0;
                        FileStream fileTemp = null;
                        while (fileTemp == null)
                        {
                            try
                            {
                                fileTemp = new FileStream(tempPath + "\\temp" + i + ex, FileMode.Open, FileAccess.Read);
                                tryTimes++;
                                if (tryTimes > 100) //次数大于100就结束等待
                                {
                                    return Json(new {error = true});
                                }
                            }
                            catch (Exception)
                            {
                            }
                        }


                        int buffersize = Convert.ToInt32(fileTemp.Length);

                        fileTemp.Read(buffer, 0, buffersize);
                        fa.Write(buffer, 0, buffersize);

                        //fileTemp.Read(buffer, 0, 10*1024*1024);
                        //fa.Write(buffer, 0, 10 * 1024 * 1024);


                        fileTemp.Flush();
                        //fileTemp.Close();
                        fileTemp.Dispose();


                        if (i == count - 1)
                        {
                            TempFolder.Delete(true); //删除temp目录 
                        }
                    }


                    #region 将文件信息写入数据库

                    FileModel model = new FileModel();
                    FileUpload.Models.FileInfo upfile = new FileUpload.Models.FileInfo();
                    upfile.FileMD5 = md5value;
                    upfile.FileName = filefullname;
                    model.FileInfoSet.Add(upfile);
                    model.SaveChanges();

                    #endregion

                    fa.Flush();
                    //fa.Close();//关闭流
                    fa.Dispose();
                }
            }

            return Json(new
            {
                jsonrpc = "2.0",
                id = id,
                filePath = "/Upload/" + fileFullName
            });
        }


        public ActionResult IsMD5Exist(string fileMd5, string fileName, string fileID)
        {
            FileModel model = new FileModel();
            FileUpload.Models.FileInfo file = new FileUpload.Models.FileInfo();
            file = (from c in model.FileInfoSet
                where c.FileMD5 == fileMd5
                select c).FirstOrDefault();
            //if (file == null)
            //{
            //    return HttpNotFound();//代表服务器上没有这个文件
            //}

            //return Json(new//存在MD5相同的文件
            //{
            //    Eixst = true
            //});
            if (file == null)
            {
                return Json("this file is not exist");
            }

            return Json("this file is exist");
        }
    }
}

ImagUpload文件夹下Index.cshtml

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <title>图片上传</title>
    <!--支持IE9+ chrome fireFox-->
    <script src="~/Scripts/jquery-2.1.4.min.js"></script>
    <link href="~/Content/webuploader.css" rel="stylesheet"/>
    <script src="~/Scripts/webuploader.nolog.js"></script>
    <link href="~/Content/bootstrap.min.css" rel="stylesheet"/>
    <script src="~/Scripts/bootstrap.min.js"></script>
    <script type="text/javascript">
        $(function() {
            $list = $('#fileList');
            var thumbnailHeight = 150;
            var thumbnailWidth = 150;
            //WebUploader实例
            var uploader = WebUploader.create({


                //设置选完文件后是否自动上传
                auto: false,


                //swf文件路径
                //swf: BASE_URL + '~/FileUpload/Uploader.swf',
                swf: '../FileUpload/Uploader.swf',

                // 文件接收服务端。
                server: '/ImagUpload/ImagUp',

                // 选择文件的按钮。可选。
                // 内部根据当前运行是创建,可能是input元素,也可能是flash.
                pick: '#picker',


                // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
                //resize: false

                //选择图片文件
                accept: {
                    title: 'Images',
                    extensions: 'gif,jpg,jpeg,bmp,png',
                    mimeTypes: 'image/*'
                }
            });

            // 当有文件被添加进队列的时候
            uploader.on('fileQueued',
                function(file) {
                    //$list.append('<div id="' + file.id + '" class="item">' +
                    //    '<h4 class="info">' + file.name + '<button type="button" fileId="' + file.id + '" class="btn btn-danger btn-delete"><span class="glyphicon glyphicon-trash"></span></button></h4>' +
                    //    '<p class="state">等待上传...</p>' +
                    //    '</div>');
                    var $li = $('<div id="' +
                            file.id +
                            '" class="item">' +
                            '<h4 class="info">' +
                            file.name +
                            '<button type="button" fileId="' +
                            file.id +
                            '" class="btn btn-danger btn-delete"><span class="glyphicon glyphicon-trash"></span></button></h4>' +
                            '<p class="state">等待上传...</p>' +
                            '<img>' +
                            '</div>'),
                        $img = $li.find('img');
                    // $list为容器jQuery实例
                    $list.append($li);
                    //创建缩略图
                    uploader.makeThumb(file,
                        function(error, src) {
                            if (error) {
                                $img.replaceWith('<span>不能预览</span>');
                                return;
                            }

                            $img.attr('src', src);
                        },
                        thumbnailWidth,
                        thumbnailHeight);
                    //删除要上传的文件
                    //每次添加文件都给btn-delete绑定删除方法
                    $(".btn-delete").click(function() {
                        //console.log($(this).attr("fileId"));//拿到文件id
                        uploader.removeFile(uploader.getFile($(this).attr("fileId"), true));
                        $(this).parent().parent().fadeOut(); //视觉上消失了
                        $(this).parent().parent().remove(); //DOM上删除了
                    });
                });


            // 文件上传过程中创建进度条实时显示。
            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="width: 0%">' +
                            '</div>' +
                            '</div>').appendTo($li).find('.progress-bar');
                    }

                    $li.find('p.state').text('上传中');

                    $percent.css('width', percentage * 100 + '%');
                });


            uploader.on('uploadSuccess',
                function(file) {
                    $('#' + file.id).find('p.state').text('已上传');
                    $('#' + file.id).find(".progress").find(".progress-bar")
                        .attr("class", "progress-bar progress-bar-success");
                    $('#' + file.id).find(".info").find('.btn').fadeOut('slow'); //上传完后删除"删除"按钮
                });

            uploader.on('uploadError',
                function(file) {
                    $('#' + file.id).find('p.state').text('上传出错');
                    //上传出错后进度条爆红
                    $('#' + file.id).find(".progress").find(".progress-bar")
                        .attr("class", "progress-bar progress-bar-danger");
                    //添加重试按钮
                    //为了防止重复添加重试按钮,做一个判断
                    //var retrybutton = $('#' + file.id).find(".btn-retry");
                    //$('#' + file.id)
                    if ($('#' + file.id).find(".btn-retry").length < 1) {
                        var btn = $('<button type="button" fileid="' +
                            file.id +
                            '" class="btn btn-success btn-retry"><span class="glyphicon glyphicon-refresh"></span></button>');
                        $('#' + file.id).find(".info").append(btn); //.find(".btn-danger")
                    }


                    $(".btn-retry").click(function() {
                        //console.log($(this).attr("fileId"));//拿到文件id
                        uploader.retry(uploader.getFile($(this).attr("fileId")));

                    });

                });

            uploader.on('uploadComplete',
                function(file) { //上传完成后回调
                    //$('#' + file.id).find('.progress').fadeOut();//上传完删除进度条
                    //$('#' + file.id + 'btn').fadeOut('slow')//上传完后删除"删除"按钮
                });

            uploader.on('uploadFinished',
                function() {
                    //上传完后的回调方法
                    //alert("所有文件上传完毕");
                    //提交表单
                });

            $("#UploadBtn").click(function() {
                uploader.upload(); //上传
            });

            uploader.on('uploadAccept',
                function(file, response) {
                    //if (uploader.errorCode) {
                    //    // 通过return false来告诉组件,此文件上传有错。
                    //    return false;
                    //}
                    if (response._raw == '{"error":true}') {
                        return false;
                    }
                });
            //重传指定文件
            //function retry(file) {
            //    uploader.retry(file);
            //}


        });


    </script>

</head>
<body>
<div class="container" style="margin-top: 50px">
    <div id="uploader" class="container">
        <div class="container">
            <div id="fileList" class="uploader-list"></div> <!--存放文件的容器-->
        </div>
        <div class="btns container">
            <div id="picker" class="webuploader-container" style="float: left; margin-right: 10px">
                <div>
                    选择图片
                    <input type="file" name="file" class="webuploader-element-invisible" multiple="multiple">
                </div>
            </div>

            <div id="UploadBtn" class="webuploader-pick" style="float: left">开始上传</div>
        </div>
    </div>
</div>

</body>
</html>

ImagUploadController.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace FileUpload.Controllers
{
    public class ImagUploadController : FileBaseController
    {
        public ViewResult Index()
        {
            return View();
        }

        // GET: ImagUpload
        //解决文件上传最大4M的显示可在web.config中设置,当前设置,最大上传大小2GB,最大上传时间一小时
        public ActionResult ImagUp(string id, string name, string type, string lastModifiedDate, int size,
            HttpPostedFileBase file)
        {
            #region 判断文件后缀名

            string ex = Path.GetExtension(file.FileName).ToLower(); //要统一转成大写或者小写
            if (!IsFileExAcceptable(ex))
            {
                return Json(new {error = true});
            }

            #endregion


            #region 或者: 验证文件类型file.ContentType,其实也是验证文件后缀

            //if (file.ContentType != "image/gif" && file.ContentType != "image/jpg" && file.ContentType != "image/jpeg" && file.ContentType != "image/bmp" && file.ContentType != "image/png")
            //{
            //    //文件类型不符合要求
            //    return Json(new { jsonrpc = 2.0, error = new { code = 102, message = "保存失败" }, id = "id" });
            //}

            #endregion


            #region 真正验证文件类型!改后缀也不行

            //FileStream fs = (FileStream)file.InputStream;
            Stream fs = file.InputStream;
            BinaryReader br = new BinaryReader(fs);
            if (!IsRealImag(fs, br))
            {
                return Json(new {error = true});
            }

            #endregion


            //开始保存文件
            string fileFullName = String.Empty;
            string localPath = Path.Combine(HttpRuntime.AppDomainAppPath, "Upload");
            if (Request.Files.Count == 0)
            {
                //return HttpNotFound();
                //return Json(new { jsonrpc = 2.0, error = new { code = 102, message = "保存失败" }, id = id });
                return Json(new {error = true}); //新的错误返回方式,更加轻量!
            }

            fileFullName = Guid.NewGuid().ToString("N") + ex;

            if (!SaveFile(localPath, fileFullName, file))
            {
                return Json(new {error = true});
            }
            else
            {
                return Json(new
                {
                    jsonrpc = "2.0",
                    id = id,
                    filePath = "/Upload/" + fileFullName
                });
            }

            #region 方法移到了FileBaseController

            //if (!System.IO.Directory.Exists(localPath))
            //{
            //    System.IO.Directory.CreateDirectory(localPath);
            //}
            //try
            //{
            //    file.SaveAs(Path.Combine(localPath, fileFullName));
            //}
            //catch (Exception)
            //{
            //    //异常处理   Log4Net 
            //    //return HttpNotFound();
            //    return Json(new { error = true });//新的错误返回方式,更加轻量!
            //}
            //finally
            //{
            //    br.Close();
            //    fs.Close();
            //}
            //return Json(new
            //{
            //    jsonrpc = "2.0",
            //    id = id,
            //    filePath = "/Upload/" + fileFullName
            //}); 

            #endregion
        }

        /// <summary>
        /// 判断文件后缀名是否可接受
        /// </summary>
        /// <param name="ex">.后缀名</param>
        /// <returns></returns>
        public bool IsFileExAcceptable(string ex)
        {
            //做文件类型验证 文件后缀名统一为小写

            //gif,jpg,jpeg,bmp,png
            if (ex != ".gif" && ex != ".jpg" && ex != ".jpeg" && ex != ".bmp" && ex != ".png")
            {
                //文件后缀不符合要求

                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 真正的通过fileclass验证是否是真的图片,改后缀名也能验证出来
        /// </summary>
        /// <param name="fs">文件输入流</param>
        /// <param name="br">二进制读入</param>
        /// <returns></returns>
        public bool IsRealImag(Stream fs, BinaryReader br)
        {
            //Stream fs = file.InputStream;
            string fileClass = string.Empty;
            //BinaryReader br = new BinaryReader(fs);
            byte buffer;
            byte[] b = new byte[2];
            buffer = br.ReadByte();
            b[0] = buffer;
            fileClass = buffer.ToString();
            buffer = br.ReadByte();
            b[1] = buffer;
            fileClass += buffer.ToString();

            //br.Close(); 释放资源在finally语句块中,提前释放会将file的内容清空
            //fs.Close();
            if (fileClass != "7173" && fileClass != "255216" && fileClass != "6677" && fileClass != "13780"
            ) //jpe和jpeg fileclass相同
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}

Web.config

<?xml version="1.0"?>

<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  http://go.microsoft.com/fwlink/?LinkId=301880
  -->
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework"
             type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
             requirePermission="false" />
  </configSections>
  <appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
  <!--
    有关 web.config 更改的说明,请参见 http://go.microsoft.com/fwlink/?LinkId=235367。

    可在 <httpRuntime> 标记上设置以下特性。
      <system.Web>
        <httpRuntime targetFramework="4.5" />
      </system.Web>
  -->
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime maxRequestLength="1048576" executionTimeout="3600" />
    <!--设置最大上传大小和时间-->
    <pages controlRenderingCompatibilityVersion="4.0" />
  </system.web>
  <system.webServer>
    <!--configuration/system.webServer/security/requestFiltering/requestLimits@maxAllowedContentLength-->
    <modules>
      <remove name="FormsAuthentication" />
    </modules>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="2147483647">
          <!--最大上传2GB-->
        </requestLimits>
      </requestFiltering>
    </security>
  </system.webServer>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs"
                type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
                type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                warningLevel="4"
                compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
    </compilers>
  </system.codedom>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient"
                type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
  <connectionStrings>
    <add name="FileModel"
         connectionString="data source=.;initial catalog=FileUpload;integrated security=True;user id=sa;password=wu199010;MultipleActiveResultSets=True;App=EntityFramework"
         providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

截图

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值