第六节:基于LayUI组件的文件上传 和 基于dropzonejs的文件上传

一. 接口设计

1. 说明

 设计异步方法,这里采用文件流的形式进行存储,设计两个接口,分别用来处理单文件上传和多文件上传.

2. 大致思路

 获取文件→判空→获取文件名和扩展名→设置存放绝对路径(若不存在,则新建)→编辑文件保存名称(这里随机命名,所以不用判重) →拼接最终路径进行保存→DB中存储相对路径→返回前端成功和相对路径.

3. 其它

 可以通过 .Length,来获取文件的大小

代码分享: 

        #region 01-单文件上传
        /// <summary>
        /// 单文件上传
        /// </summary>
        /// <param name="_hostingEnvironment"></param>
        /// <returns></returns>
        public async Task<IActionResult> SingleSaveFile([FromServices] IWebHostEnvironment _hostingEnvironment)
        {
            try
            {
                long size = 0;   //统计上传文件的大小(单位b)
                var files = Request.Form.Files;  //获取文件
                if (files.Count == 0)
                {
                    return Json(new { status = "error", msg = "上传内容为空", data = "" });
                }

                //获取文件扩展名
                var fileName = files[0].FileName;
                int idxStart = fileName.LastIndexOf(".");
                string areviation = fileName.Substring(idxStart, fileName.Length - idxStart);

                //编辑文件的存储路径
                var filePath = _hostingEnvironment.ContentRootPath + @"DownLoadPicture";
                if (!Directory.Exists(filePath))
                {
                    Directory.CreateDirectory(filePath);
                }
                //编辑文件的名称(目前是随机命名,如果用原名保存,需要判重)
                var myFileName = $"{Guid.NewGuid().ToString()}{areviation}";
                //最终路径
                var finalPath = filePath + myFileName;
                size += files[0].Length;
                using (FileStream fs = System.IO.File.Create(finalPath))
                {
                    await files[0].CopyToAsync(fs);
                    await fs.FlushAsync();
                }

                //DB中存储的或者返回给前端的都是相对路径
                string relativeUrl = $"/DownLoad/Picture/{myFileName}";

                return Json(new { status = "ok", msg = "上传成功", data = relativeUrl });
            }
            catch (Exception ex)
            {
                return Json(new { status = "error", msg = "上传失败", data = "" });
            };
        }
        #endregion

        #region 02-多文件上传
        /// <summary>
        /// 多文件上传
        /// </summary>
        /// <param name="_hostingEnvironment"></param>
        /// <returns></returns>
        public async Task<IActionResult> ManySaveFile([FromServices] IWebHostEnvironment _hostingEnvironment)
        {
            try
            {
                long size = 0;   //统计上传文件的大小(单位b)
                var files = Request.Form.Files;  //获取文件
                if (files.Count == 0)
                {
                    return Json(new { status = "error", msg = "上传内容为空", data = "" });
                }
                List<string> rUrlList = new List<string>();
                //多文件遍历上传
                foreach (var file in files)
                {
                    //获取文件扩展名
                    var fileName = file.FileName;
                    int idxStart = fileName.LastIndexOf(".");
                    string areviation = fileName.Substring(idxStart, fileName.Length - idxStart);

                    //编辑文件的存储路径
                    var filePath = _hostingEnvironment.ContentRootPath + @"DownLoadPicture";
                    if (!Directory.Exists(filePath))
                    {
                        Directory.CreateDirectory(filePath);
                    }
                    //编辑文件的名称(目前是随机命名,如果用原名保存,需要判重)
                    var myFileName = $"{Guid.NewGuid().ToString()}{areviation}";
                    //最终路径
                    var finalPath = filePath + myFileName;
                    size += file.Length;
                    using (FileStream fs = System.IO.File.Create(finalPath))
                    {
                        await file.CopyToAsync(fs);
                        await fs.FlushAsync();
                    }

                    //DB中存储的或者返回给前端的都是相对路径
                    string relativeUrl = $"/DownLoad/Picture/{myFileName}";
                    rUrlList.Add(relativeUrl);

                }
                return Json(new { status = "ok", msg = "上传成功", data = rUrlList });
            }
            catch (Exception ex)
            {
                return Json(new { status = "error", msg = "上传失败", data = "" });
            };
        } 
        #endregion
View Code

二. 基于LayUI文件上传

1.相关地址

 官方文档:https://www.layui.com/doc/modules/upload.html

 官方样例:https://www.layui.com/demo/upload.html

2. 各种样例

(1). 单文件上传

 A.基础配置:Header表头、data参数、acceptMime筛选文件类型、accept+exts允许上传的文件和后缀、Size最大上传大小等

 B.几个回调:choose选择文件后回调、before文件提交前回调、done上传成功后回调、error请求异常回调

代码分享:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>文件上传</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <link href="~/src/layuiadmin/layui/css/layui.css" rel="stylesheet" />
    <link href="~/src/layuiadmin/style/admin.css" rel="stylesheet" />
    <style>
        .c1 {
            width: 500px;
            height: 280px;
            border: 1px solid black;
            padding: 20px;
            float: left;
        }

        img {
            width: 200px;
            height: 200px;
        }
    </style>
</head>
<body>
    <div class="c1">
        <button type="button" class="layui-btn" id="test1">
            单文件上传(各种属性)
        </button>
        <br />
        <div>
            <img src="/DownLoad/Picture/demo.png" id="j_img1" />
        </div>

    </div>

    

    <script src="~/src/layuiadmin/layui/layui.js"></script>
    <script>
        layui.use(['upload', 'jquery'], function () {
            var $ = layui.$;
            var upload = layui.upload;

            //1.单文件上传
            var uploadInst1 = upload.render({
                elem: '#test1',               //绑定元素
                url: 'SingleSaveFile',        //上传接口
                headers: { auth: window.localStorage.getItem("token") },  //表头
                data: {},                     //额外参数
                acceptMime: 'image/*',        //选择框筛选文件类型(不是很准确)
                accept: "file",               //允许上传所有文件
                //exts:"zip|rar|7z",                    //允许上传的后缀的类型,和accept配合使用
                size: 0,                      //设置文件最大可允许上传的大小,单位 KB, 0表示不限制
                choose: function (obj) {
                    //选择文件后回调
                },
                before: function () {
                    //文件提交前回调
                    layer.load(); //上传loading
                },
                done: function (res) {
                    //上传成功后回调
                    if (res.status == "ok") {
                        alert(res.msg);
                        $("#j_img1").attr("src", res.data);

                        layer.closeAll('loading'); //关闭loading
                    }
                },
                error: function (index, upload) {
                    //请求异常回调

                    layer.closeAll('loading'); //关闭loading
                }
            });

          

        });
    </script>


</body>
</html>
View Code

运行效果:

(2).多文件上传

A. 原理

 LayUI的多文件上传只是一次可以选多个文件而已,是通过调用多次接口实现的,目前没有实现调用一次接口,所以这里还是调用SingleSaveFile,对于前端而言done回调每成功1个文件回调1次, allDone当所有文件提交后才能被触发,会返回文件总数、成功文件数、失败文件数。

B. 核心配置

 (1). multiple: true,  //允许多文件上传

 (2). number: 2,  //允许上传的文件数量,配合multiple使用

代码分享:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>文件上传</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <link href="~/src/layuiadmin/layui/css/layui.css" rel="stylesheet" />
    <link href="~/src/layuiadmin/style/admin.css" rel="stylesheet" />
    <style>
        .c1 {
            width: 500px;
            height: 280px;
            border: 1px solid black;
            padding: 20px;
            float: left;
        }

        img {
            width: 200px;
            height: 200px;
        }
    </style>
</head>
<body>

    <div class="c1">
        <button type="button" class="layui-btn" id="test2">
            多文件上传
        </button>
        <br />
        <div id="j2">
        </div>
    </div>

  

    <script src="~/src/layuiadmin/layui/layui.js"></script>
    <script>
        layui.use(['upload', 'jquery'], function () {
            var $ = layui.$;
            var upload = layui.upload;
         
            //2.多文件上传
            var uploadInst2 = upload.render({
                elem: '#test2',               //绑定元素
                url: 'SingleSaveFile',        //上传接口
                headers: { auth: window.localStorage.getItem("token") },  //表头
                data: {},                     //额外参数
                acceptMime: 'image/*',        //选择框筛选文件类型(不是很准确)
                accept: "file",               //允许上传所有文件
                //exts:"zip|rar|7z",          //允许上传的后缀的类型,和accept配合使用
                size: 0,                      //设置文件最大可允许上传的大小,单位 KB, 0表示不限制
                multiple: true,               //允许多文件上传
                number: 2,                    //允许上传的文件数量,配合multiple使用
                choose: function (obj) {
                    //选择文件后回调
                },
                before: function () {
                    //文件提交前回调
                    layer.load(); //上传loading
                },
                allDone: function (obj) {
                    //当文件全部被提交后,才触发
                    console.log(obj.total); //得到总文件数
                    console.log(obj.successful); //请求成功的文件数
                    console.log(obj.aborted); //请求失败的文件数

                    layer.closeAll('loading'); //关闭loading
                },
                done: function (res) {
                    //上传成功后回调(每成功一个文件,回调一次)
                    if (res.status == "ok") {
                        $("#j2").append('<img src="' + res.data + '"/>');
                    }
                },
                error: function (index, upload) {
                    //请求异常回调
                    //当上传失败时,你可以生成一个“重新上传”的按钮,点击该按钮时,执行 upload() 方法即可实现重新上传

                    layer.closeAll('loading'); //关闭loading
                }
            });

        
        });
    </script>


</body>
</html>
View Code

运行效果:

(3).非自动上传+队列

大致流程:

 通过 auto: false设置不自动上传,然后通过 bindAction: '#test33' 指向一个按钮绑定上传,选择文件后进入choose回调,将文件存放到本地队列中,并且可以操作DOM,用于提前预览,上传成功后,修改本地DOM或者删除; 上传失败后,将本地DOM改为重新上传。

代码分享:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>文件上传</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <link href="~/src/layuiadmin/layui/css/layui.css" rel="stylesheet" />
    <link href="~/src/layuiadmin/style/admin.css" rel="stylesheet" />
    <style>
        .c1 {
            width: 500px;
            height: 280px;
            border: 1px solid black;
            padding: 20px;
            float: left;
        }

        img {
            width: 200px;
            height: 200px;
        }
    </style>
</head>
<body>

    <div class="c1">
        <button type="button" class="layui-btn" id="test3">
            非自动上传+队列
        </button>
        <button type="button" class="layui-btn" id="test33">
            点我上传
        </button>
        <br />
        <div id="j3">
        </div>
    </div>

    <script src="~/src/layuiadmin/layui/layui.js"></script>
    <script>
        layui.use(['upload', 'jquery'], function () {
            var $ = layui.$;
            var upload = layui.upload;

            //3.非自动上传+队列
            var uploadInst3 = upload.render({
                elem: '#test3',               //绑定元素
                url: 'SingleSaveFile',        //上传接口
                headers: { auth: window.localStorage.getItem("token") },  //表头
                data: {},                     //额外参数
                acceptMime: 'image/*',        //选择框筛选文件类型(不是很准确)
                accept: "file",               //允许上传所有文件
                //exts:"zip|rar|7z",          //允许上传的后缀的类型,和accept配合使用
                size: 0,                      //设置文件最大可允许上传的大小,单位 KB, 0表示不限制
                multiple: true,               //允许多文件上传
                number: 2,                    //允许上传的文件数量,配合multiple使用
                auto: false,                   //选择文件后不自动上传
                bindAction: '#test33', //指向一个按钮触发上传
                choose: function (obj) {
                    //选择文件后回调
                    //将每次选择的文件追加到文件队列
                    var files = obj.pushFile();
                    //预读本地文件,如果是多文件,则会遍历。(不支持ie8/9)
                    obj.preview(function (index, file, result) {
                        console.log(index); //得到文件索引
                        console.log(file); //得到文件对象
                        //console.log(result); //得到文件base64编码,比如图片
                        //obj.resetFile(index, file, '123.jpg'); //重命名文件名,layui 2.3.0 开始新增

                        //这里还可以做一些 append 文件列表 DOM 的操作
                        var tr = $(['<tr id="upload-' + index + '">'
                            , '<td>' + file.name + '</td>'
                            , '<td>' + (file.size / 1024).toFixed(1) + 'kb</td>'
                            , '<td>等待上传</td>'
                            , '<td>'
                            , '<button class="layui-btn layui-btn-xs demo-reload layui-hide">单个重传</button>'
                            , '<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>'
                            , '</td>'
                            , '</tr>'].join(''));

                        //单个重传(上传失败的时候配置成显示)
                        tr.find('.demo-reload').on('click', function () {
                            obj.upload(index, file);
                        });

                        //删除
                        tr.find('.demo-delete').on('click', function () {
                            delete files[index]; //删除对应的文件
                            tr.remove();
                            uploadInst3.config.elem.next()[0].value = ''; //清空 input file 值,以免删除后出现同名文件不可选
                        });

                        $("#j3").append(tr);


                        //obj.upload(index, file); //对上传失败的单个文件重新上传,一般在某个事件中使用
                        //delete files[index]; //删除列表中对应的文件,一般在某个事件中使用
                    });


                },
                before: function () {
                    //文件提交前回调
                    //layer.load(); //上传loading
                },
                allDone: function (obj) {
                    //当文件全部被提交后,才触发

                },
                done: function (res) {
                    //上传成功后回调(每成功一个文件,回调一次)
                    if (res.status == "ok") {
                        $("#j3").append('<img src="' + res.data + '"/>');

                        //删除列表中待上传的文件(或者改里面的内容,改成上传成功)
                    }
                },
                error: function (index, upload) {
                    //请求异常回调
                   //配置上面显示重传按钮

                }
            });

        });
    </script>


</body>
</html>
View Code

运行效果: 

三. 基于dropzonejs文件上传

1. 相关地址

 官网:https://www.dropzonejs.com/ (含文档和下载地址)

2. 各种样例

(1).单文件上传

 maxFiles: 1 将该属性设置为1,只能选择一个文件上传。

 另外:该控件默认会生成一个缩略图框,我们很多情况下不需要,可以采用下面的方式来解决。

 previewsContainer: '#hid', //将缩略图存放到指定位置(然后将该位置隐藏,则不显示缩略图了)

(2).多文件上传

A.原理:这里的多文件上传只调用一次接口!!

B.核心配置:

 uploadMultiple: true, //开启单次请求上传多个文件, 配合下面的parallelUploads适用

 parallelUploads: 6, //并行允许上传文件的个数

 maxFiles: 6, //一次性上传的文件数量上限

 successmultiple和errormultiple //多文件成功回调 和 失败回调 (只调一次)

代码分享:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>样例1</title>
        <style>
            .c1 {
                    width: 600px;
                    height: 280px;
                    border: 1px solid black;
                    padding: 20px;
                    float: left;
                }
        
             img {
                    width: 150px;
                    height: 150px;
                }
            </style>
        <script src="../../../js/easyui/jquery.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../../js/utils/dropzone.js" type="text/javascript" charset="utf-8"></script>

        <script type="text/javascript">
            $(function() {
                // 单文件上传
                $("#test1").dropzone({
                    url: "http://localhost:29793/Demo_Areas/Demo1/SingleSaveFile",
                    method: 'post',
                    createImageThumbnails: false, //前端不生成缩略图(只是不生成图,但缩略框还在)
                    headers: {
                        "auth": window.localStorage.getItem("token")
                    },
                    timeout: 1000000, //超时时间,单位毫秒, 默认30s
                    maxFiles: 1, //一次性上传的文件数量上限(选择的时候最多选1个文件,无法多选)        
                    maxFilesize: 10, //最大文件上传大小 单位: MB
                    previewsContainer: '#hid', //将缩略图存放到指定位置(将该位置隐藏,则不显示缩略图了)                
                    acceptedFiles: "image/*,application/pdf,.psd,.txt", //上传的类型    
                    dictMaxFilesExceeded: "您最多只能一次上传n个文件", //替换文件数量超限的限制
                    dictInvalidFileType: '不支持该文件类型上传', //替换不支持类型上传的文案
                    dictFileTooBig: '您上传的文件太大,最大允许10M', //替换文件太大的文案
                    dictFallbackMessage: '您的浏览器不支持该上传控件', //替换浏览器不支持的文案
                    init:function(){        
                        var that=this;
                        this.on("complete",function(file){
                            // that.removeFile(file);
                            that.removeAllFiles();     //执行完毕后,删除本地记录,使其可以继续上传(类似重置控件)
                        });
                    },
                    sending: function(x1, x2, x3) {
                        //发送文件之前调用,参数详见文档
                    },
                    success: function(file, res, e) {
                        if (res.status == "ok") {
                            var myUrl = "http://localhost:29793" + res.data;
                            $("#j1").append('<img src="' + myUrl + '"/>');
                        }
                    },
                    error: function(x1, errorMsg, xhr) {
                        if (x1.status == "error") {
                            alert(errorMsg);
                        }
                    }
                });
                //多文件上传
                $("#test2").dropzone({
                    url: "http://localhost:29793/Demo_Areas/Demo1/ManySaveFile",
                    method: 'post',
                    createImageThumbnails: false, //前端不生成缩略图(只是不生成图,但缩略框还在)
                    headers: {
                        "auth": window.localStorage.getItem("token")
                    },
                    timeout: 1000000, //超时时间,单位毫秒, 默认30s
                    uploadMultiple: true, //开启单次请求上传多个文件, 配合下面的parallelUploads适用
                    parallelUploads: 6, //并行允许上传文件的个数
                    maxFiles: 3, //一次性上传的文件数量上限        
                    maxFilesize: 10, //最大文件上传大小 单位: MB
                    previewsContainer: '#hid', //将缩略图存放到指定位置(将该位置隐藏,则不显示缩略图了)                
                    acceptedFiles: "image/*,application/pdf,.psd,.txt", //上传的类型        
                    dictMaxFilesExceeded: "您最多只能一次上传n个文件", //替换文件数量超限的限制
                    dictInvalidFileType: '不支持该文件类型上传', //替换不支持类型上传的文案
                    dictFileTooBig: '您上传的文件太大,最大允许10M', //替换文件太大的文案
                    dictFallbackMessage: '您的浏览器不支持该上传控件', //替换浏览器不支持的文案
                    init:function(){
                        var that=this;
                        this.on("complete",function(file){
                            that.removeAllFiles();    //执行完毕后,删除本地记录,使其可以继续上传(类似重置控件)
                        });
                    },
                    sendingmultiple: function(x1, x2, x3) {
                        //发送文件之前调用,参数详见文档
                    },
                    //多文件成功回调, 不能适用success回调,success会触发多次
                    successmultiple: function(file, res, e) {
                        console.log(res);
                        if (res.status == "ok") {
                            for (var i = 0; i < res.data.length; i++) {
                                var myUrl = "http://localhost:29793" + res.data[i];
                                $("#j2").append('<img src="' + myUrl + '"/>');
                            }
                        }
                    },
                    errormultiple: function(x1, errorMsg, xhr) {
                        if (x1.status == "error") {
                            alert(errorMsg);
                        }
                    },
                    error: function(x1, errorMsg, xhr) {
                        if (x1.status == "error") {
                            alert(errorMsg);
                        }
                    }
                });



            });
        </script>
    </head>
    <body>
        <p>图片上传dropzone样例</p>
        <div class="c1">
            <button type="button" class="layui-btn" id="test1">
                单文件上传(各种属性)
            </button>
            <br />
            <div id="j1">
            </div>
        </div>

        <div class="c1">
            <button type="button" class="layui-btn" id="test2">
                多文件上传
            </button>
            <br />
            <div id="j2">
            </div>
        </div>


        <div id="hid" style="display: none;">
            用来存放缩略图,但不显示,目前没有找到直接关闭缩略图的属性
        </div>
    </body>
</html>
View Code

 运行截图:

3. 其它

 支持队列上传、文件分块上传、拖拽、其它各种情况的回调等等。

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
原文地址:https://www.cnblogs.com/yaopengfei/p/14307822.html