目录

需求

引入

关键代码

操作界面

​JavaScript包程序

服务端 ashx 程序

服务端上传后处理程序

小结

需求

在许多应用场景里,多文件上传是一项比较实用的功能。实际应用中,多文件上传可以考虑如下需求:

1、对上传文件的类型、大小有一个基本的控制。

2、上传文件时有一个进度显示,包括当前文件和整体进度。

3、上传后,在服务端后续事件进行一些处理。

引入

首先请在WEB应用程序根目录下创建COMMON目录,并引入 JavaScript 程序包,该程序包已经打包,下载地址为:https://download.csdn.net/download/michaelline/88615565。

下载成功后解压到COMMON目录即可,请引入如下图中的 JS 文件:

另外,我们还需要在 app_data目录下创建 ajaxUploadFiles 子目录,以备上传创建文件使用。

关键代码

操作界面

界面上放置标准的 input file 控件,并将其服务器化,即 runat="server"。点击选择文件,选中所有目标文件后,自动实现文件上传功能。

示例界面如下:

示例UI代码如下:

onbeginupload="ajax_uploadFiles_beginUpload" onprogressupload="ajax_uploadFiles_progressUpload" onendupload="ajax_uploadFiles_endUpload"

multiple="multiple" allowtype="pptx|docx|mp3|txt|std" allowsize="500m|100m" fileindex="0" name="fileupload"

serverbuttonid="ajaxEndBtn" serverfilelistid="ajaxReturnFileName"

progresspanelid="ajaxMfileProgressPanel"

onchange="ajax_uploadFiles(this);return false" />




input file 控件的一些设置如下:

(1)onbeginupload="ajax_uploadFiles_beginUpload"   js方法,开始上传前事件,默认值

(2)onprogressupload="ajax_uploadFiles_progressUpload"   js方法,上传中事件,默认值

(3)onendupload="ajax_uploadFiles_endUpload"    js方法,选择完文件上传事件,默认值 (4)multiple="multiple"         控件属性,允许多文件选中上传

(5)allowtype="pptx|docx|mp3|txt|std"    自定义属性,允许上传的文件类型,以 | 分隔

(6)allowsize="500m|100m"    自定义属性,允许上传的文件最大尺寸,可以以 | 分隔,并一一对应,如果不对应,则根据 allowtype 的设置从左至右进行匹配

        如举例中的设置则表示为,pptx 允许最大 500M , docx 最大 100M,后面未设置则均为100M

(7) serverbuttonid="ajaxEndBtn"   自定义属性,执行的服务器按钮ID,默认值 

(8)serverfilelistid="ajaxReturnFileName"  自定义属性,服务器端返回的文件ID列表,默认值

(9)οnchange="ajax_uploadFiles(this);return false"  自定义属性,js方法,选择文件后自动执行上传功能,默认值

根据示例代码的设置,以上部分除了 allowtype和 allowsize 均可以不用改变设置。

上传中的效果如下图:

 

JavaScript包程序

本包程序实现了前面设置的界面元素方法、事件、属性的实现及对文件上传的客户端控制,示例代码如下:

 //批量上传文件的内置默认辅助方法,表示每上传一个文件之前发生的事件,

         //事件的fileObj参数代表 file对象(上传控件),由主方法自动传入,开发者可以重新指定自定义方法

         function ajax_uploadFiles_beginUpload(fileObj) {

            var fIndex = parseInt(fileObj.getAttribute("fileindex"), 10);

            if (fIndex == 0) {

                document.getElementById('ajax_uploadFiles_serverProcessTip').innerHTML = '';

                document.getElementById("ajax_uploadFiles_upprogress").innerHTML = "";

                document.getElementById("ajax_uploadFiles_cprogress").innerHTML = "";

                document.getElementById("ajax_uploadFiles_totalprogress").style.width = "0px";

                document.getElementById(fileObj.getAttribute("serverfilelistid")).value = "";

            }

            document.getElementById("ajax_uploadFiles_curfilename").innerHTML = fileObj.files[fIndex].name;

        }

        //批量上传文件的内置默认辅助方法,表示当前正在上传文件时发生的事件(主要用于显示上传进度),

        //事件的fileObj参数代表 file对象(上传控件), loaded:已经上传的文件总字节, total:正在上传的文件总字数,

        // percent:不超过100的整数,表示为百分比。这些参数由主方法自动传入,开发者可以重新指定自定义方法

        function ajax_uploadFiles_progressUpload(fileObj, loaded, total, percent) {

            document.getElementById("ajax_uploadFiles_upprogress").innerHTML = ("" + percent + "%");

            var curb = parseInt(document.getElementById("ajax_uploadFiles_curbg").style.width, 10);

            document.getElementById("ajax_uploadFiles_curprogress").style.width = Math.floor(curb * loaded / total) + "px";

        }

        //批量上传文件的内置默认辅助方法,表示当前文件上传完成时发生的事件(主要用于处理文件上传后的跟踪处理,并且返回服务器上保存的文件列到一个文本框中,以|分隔),

        //事件的fileObj参数代表 file对象(上传控件), type:上传状态返回,包括success成功,error失败, 

        //data:文件的数据,暂时未使用, desfile:要保存在服务器上的文件名

        // 这些参数由主方法自动传入,开发者可以重新指定自定义方法

        function ajax_uploadFiles_endUpload(fileObj, type, data, desfile) {

            var fIndex = parseInt(fileObj.getAttribute("fileindex"), 10);

            var filecount = fileObj.files.length;

            document.getElementById(fileObj.getAttribute("serverfilelistid")).value += desfile + "|";

            var totalb = parseInt(document.getElementById("ajax_uploadFiles_totalbg").style.width, 10);

            document.getElementById("ajax_uploadFiles_totalprogress").style.width = Math.floor(totalb * (fIndex + 1) / filecount) + "px";

            document.getElementById("ajax_uploadFiles_cprogress").innerHTML = ("" + Math.floor(100 * (fIndex + 1) / filecount) + "%");

            if (fIndex < filecount - 1) {

                fIndex++;

                fileObj.setAttribute("fileindex", fIndex);

                ajax_uploadFiles(fileObj);

                return;

            }

            fileObj.setAttribute("fileindex", 0);

            if (type == "success") {

                            document.getElementById('ajaxMfile').style.display='none';

                document.getElementById('ajax_uploadFiles_serverProcessTip').innerHTML = '上传完成!正在进行后台处理...';

                document.getElementById(fileObj.getAttribute("serverbuttonid")).click();

            } else if (type == "error") {

                alert("error");

            }

        }

        //生成一个guid

        function newguid() {

            function S4() {

                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);

            }

            return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());

        }

        //批量上传文件的主方法,fileObj参数代表 file对象(上传控件)

        function ajax_uploadFiles(fileObj) {

            var formData = new FormData();

            var fIndex = parseInt(fileObj.getAttribute("fileindex"), 10);

            var filecount = fileObj.files.length;

            if (filecount == 0) {

                alert('请先浏览选择文件...');

                return;

            }

            var uploadSessionId = newguid();

            var upfile = fileObj.files[fIndex].name;

            var dotpos = upfile.lastIndexOf('.');

            var desfile = "";

            var exname = "";

            if (dotpos > 0) {

                exname = upfile.substring(dotpos + 1, upfile.length);

                desfile = uploadSessionId + upfile.substring(0, dotpos) + '.' + exname;

            } else {

                desfile = uploadSessionId + upfile;

            }

            //        alert(Math.round(upsize / 1024));

            if (fIndex == 0) {

                var allowtype = fileObj.getAttribute("allowtype");

                var allowsize = fileObj.getAttribute("allowsize");

                var at = allowtype.split('|');

                var as = allowsize.split('|');

                for (var j = 0; j < filecount; j++) {

                    var validfile = fileObj.files[j].name;

                    var upsize = fileObj.files[j].size;

                    var validdotpos = validfile.lastIndexOf('.');

                    var validexname = "";

                    if (validdotpos > 0) {

                        validexname = validfile.substring(validdotpos + 1, validfile.length);

                    }

                    var i = 0;

                    if (allowtype != "") {

                        var find = false;

                        for (i = 0; i < at.length; i++) {

                            if (at[i].toLowerCase() == validexname.toLowerCase()) {

                                find = true;

                                break;

                            }

                        }

                        if (find == false) {

                            alert("文件" + validfile + "上传的类型不符合要求!仅允许上传扩展名为:" + allowtype.split("|").join("、") + "的文件。");

                            fileObj.style.display = '';

                            document.getElementById(fileObj.getAttribute("progresspanelid")).style.display = 'none';

                            var t = fileObj;

                            t.outerHTML = t.outerHTML;

                            return;

                        }

                    }

                    if (allowsize != "") {

                        if (at.length <= as.length) {

                        } else {

                            i = 0;

                        }

                        as[i] = as[i].toLowerCase();

                        var csize = parseInt(as[i]);

                        var tsize = upsize;

                        if (as[i].lastIndexOf('k') != -1) {

                            csize = csize * 1024;

                            tsize = Math.round(upsize / 1024) + "KB";

                        } else if (as[i].lastIndexOf('m') != -1) {

                            csize = csize * 1024 * 1024;

                            tsize = Math.round(upsize / 1024 / 1024) + "MB";

                        } else if (as[i].lastIndexOf('g') != -1) {

                            csize = csize * 1024 * 1024 * 1024;

                            tsize = Math.round(upsize / 1024 / 1024 / 1024) + "GB";

                        } else if (as[i].lastIndexOf('t') != -1) {

                            csize = csize * 1024 * 1024 * 1024 * 1024;

                            tsize = Math.round(upsize / 1024 / 1024 / 1024 / 1024) + "TB";

                        }

                        if (upsize > csize) {

                            alert("上传文件" + validfile + "的大小近" + tsize + ",系统规定大小不能超过" + as[i].toUpperCase() + ",请重新选择。");

                            fileObj.style.display = '';

                            document.getElementById(fileObj.getAttribute("progresspanelid")).style.display = 'none';

                            var t = fileObj;

                            t.outerHTML = t.outerHTML;

                            return;

                        }

                    }

                } //j

            } // findex

            //        document.getElementById(callObjId).disabled = 'disabled';

            //        if (beginFuncName != null) {

            //            beginFuncName(fIndex, filecount,upfile);

            //        }

            fileObj.style.display = 'none';

            document.getElementById(fileObj.getAttribute("progresspanelid")).style.display = '';

            var findfunc = fileObj.getAttribute("onbeginupload");

            if (eval(findfunc)) {

                var execfunc = eval(findfunc);

                //            alert(findfunc);

                execfunc(fileObj);

            }

            formData.append("file", fileObj.files[fIndex]); //append()里面的第一个参数file对应permission/upload里面的参数file

            var processUploadUrl = window.location.protocol + "//" + window.location.host + "//common//uploadfile.ashx?guid=" + uploadSessionId;

            $.ajax({

                type: "post",

                async: true,  //这里要设置异步上传,才能成功调用myXhr.upload.addEventListener('progress',function(e){}),progress的回掉函数

                Accept: 'text/html;charset=UTF-8',

                data: formData,

                contentType: "multipart/form-data",

                url: processUploadUrl,

                processData: false, // 告诉jQuery不要去处理发送的数据

                contentType: false, // 告诉jQuery不要去设置Content-Type请求头

                xhr: function () {

                    myXhr = $.ajaxSettings.xhr();

                    if (myXhr.upload) { // check if upload property exists

                        myXhr.upload.addEventListener('progress', function (e) {

                            var loaded = e.loaded;                  //已经上传大小情况 

                            var total = e.total;                      //附件总大小 

                            var percent = Math.floor(100 * loaded / total);     //已经上传的百分比  

                            //                        if (progressFuncName != null) {

                            //                            progressFuncName(loaded, total, percent);

                            //                        }

                            var findfunc = fileObj.getAttribute("onprogressupload");

                            if (eval(findfunc)) {

                                var execfunc = eval(findfunc);

                                //            alert(findfunc);

                                execfunc(fileObj, loaded, total, percent);

                            }

                            //                            $("#processBar").css("width", percent);

                        }, false); // for handling the progress of the upload

                    }

                    return myXhr;

                },

                success: function (data) {

                    if (fIndex == fileObj.files.length - 1) {

                        fileObj.style.display = '';

                        document.getElementById(fileObj.getAttribute("progresspanelid")).style.display = 'none';

                        var t = fileObj;

                        t.outerHTML = t.outerHTML;

                    }

                    //                if (endFuncName != null) {

                    //                    endFuncName("success", data, desfile, fIndex,filecount);

                    //                }

                    var findfunc = fileObj.getAttribute("onendupload");

                    if (eval(findfunc)) {

                        var execfunc = eval(findfunc);

                        //            alert(findfunc);

                        execfunc(fileObj, "success", data, desfile);

                    }

                },

                error: function (XMLHttpRequest, textStatus, errorThrown) {

                    alert(errorThrown);

                    if (endFuncName != null) {

                        endFuncName(fileObj, "error", null, '');

                    }

                }

            });

        } 

服务端 ashx 程序

ashx,一般处理程序(HttpHandler)是·NET众多web组件的一种。一个 httpHandler 接受并处理一个http请求,类似 Java 中的 servlet 。

本程序实现服务器端上传文件的接收和另存操作,在这里我们存为uploadfile.ashx,代码如下:

<%@ WebHandler Language="C#" Class="Handler" %>

using System;

using System.Web;

using System.IO;

public class Handler : IHttpHandler {

    

    public void ProcessRequest (HttpContext context) {

        if (context.Request.Files.Count > 0)

        {

            //HttpContext.Current.Request.FilePath;

            string strPath = System.Web.HttpContext.Current.Server.MapPath("~/app_data/ajaxUploadFiles/");

            string strName = context.Request.Files[0].FileName;

            string ext=Path.GetExtension(strName);

            string filename =HttpContext.Current.Request.QueryString["guid"].ToString()+Path.GetFileNameWithoutExtension(strName);

            if(ext!=""){

                filename = filename  + ext;

            }

            context.Request.Files[0].SaveAs(System.IO.Path.Combine(strPath, filename));

        }

    }

 

    public bool IsReusable {

        get {

            return false;

        }

    }

}

服务端上传后处理程序

在多个文件上传到服务器后,我们需要对文件进行后期处理,在前端我们设置了ID为 “ajaxEndBtn”的服务器按钮,进行模拟调用其 click 事件。

服务器端按钮处理事件示例代码如下:

void ajaxEndBtn_Click(object sender, EventArgs e)

{

//得到保存后的文件名列表

string[] upfiles = ajaxReturnFileName.Text.Split('|');

//给予用户基本的提示

ajax_uploadFiles_serverProcessTip.Text = "本次上传分析:共计上传" + (upfiles.Length - 1).ToString() + "个文件。";

//遍历上传文件列表,进行后期处理

foreach (string filename in upfiles)

{

if (filename.Trim() == "") continue;

string upfilename = Request.PhysicalApplicationPath + "app_data\\ajaxUploadFiles\\" + filename;

string exname = System.IO.Path.GetExtension(upfilename);

//执行业务处理程序

}

 

小结

以上提供的代码仅供参考,默认的设置仅可能提供最基础的实现,比如 ashx 程序还需要进行安全控制;进度图片和UI可以重新设计;实际的业务可以根据需求对控件的属性、事件进行重写。

以上就是自己的一些分享,时间仓促,不妥之处还请大家批评指正!

参考文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。