ExtJs十四(ExtJs Mvc图片管理之五swfupload)

经过前几节系列文章,现在只剩下利用swfupload来上传图片的功能了,在ExtJs十一(ExtJs Mvc图片管理之一)中有它的下载地址和加入项目的说明。

使用swfupload最麻烦的地方是要有一个HTML元素让它嵌入加载Flash的HTML代码,而且这个HTML元素必须覆盖住Flash来实现功能,这个有点类似做单按钮的上传按钮。

现在,先为swfupload生成一个HTML元素来实现它的功能。实现方法是在显示图片的视图底部添加一个工具栏,然后将工具栏分成两部分,第一部分显示一个SPAN元素,第二部分显示一个进度条来指示上传进度。

在PicManager.js文件中,找到me.items这句代码,在它上面创建一个进度条,代码如下:

me.progress=Ext.widget("progressbar",{text:"上传进度",flex:1});

因为在swfupload的处理方法中还要直接调用进度条,因而这里将它绑定到progress属性,会方便很多。因为水平工具栏默认是使用HBox布局的,因而在进度条上设置flex为1,就会让它占满整工具栏余下的宽度。

接着在图片文件的面板内添加一个dockedItems配置项,在面板底部放置一个工具栏,并在工具栏上放置一个SPAN元素和进度条,代码如下:

                dockedItems: [
                    { xtype: "toolbar", dock: "bottom",
                        items: [
                            { xtype: "tbtext", text: "<span></span>", width: 70 },
                            me.progress
                        ]
                    }
                ]

代码中,使用了一个TextItem来显示SPAN元素,宽度为70像素。

现在,要解决的是SPAN的id问题,这也是swfupload的要求,它需要根据该id来获取元素。如果统一一个id,那就会有冲突,因而必须想办法设置成不同的id,这个就需要用Ext的id方法,它看返回一个唯一的id。

在创建进度条的代码下添加以下代码获取一个id:

me.spanid = Ext.id();

修改一下SPAN元素的代码,为它加上id,代码如下:

<span id='" + me.spanid + "'></span>

现在要做的是监听扩展的afterrender事件,在callParent代码之前添加以下代码:

me.on("afterrender",me.onAfterRender);

接着要完成的就是onAfterRender方法了,在该方法内,主要工作是完成swfupload的初始化操作,代码如下:

    onAfterRender: function(){
        var me = this;

        me.swfu = new SWFUpload({
            upload_url: "/File/Upload",
            file_size_limit: "10 MB",
            file_types: "*.jpg;*.png;*.gif;*.bmp;",
            file_types_description: "图片文件",
            file_upload_limit: 100,
            file_queue_limit: 0,
            file_post_name: "Filedata",

            swfupload_preload_handler: me.UploadPreLoad,
            swfupload_load_failed_handler: me.UploadLoadFailed,
            swfupload_loaded_handler: me.UploadLoaded,
            file_queued_handler: me.fileQueued,
            file_queue_error_handler: me.fileQueueError,
            file_dialog_complete_handler: me.fileDialogComplete,
            upload_start_handler: me.uploadStart,
            upload_progress_handler: me.uploadProgress,
            upload_error_handler: me.uploadError,
            upload_success_handler: me.uploadSuccess,
            upload_complete_handler: me.uploadComplete,
            queue_complete_handler: me.queueComplete,

            // Button settings
            button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT,
            button_image_url: '',
            button_placeholder_id: me.spanid,
            button_width: 60,
            button_height: 20,
            button_text: '上传图片',
            button_text_style: '',
            button_text_top_padding: 0,
            button_text_left_padding: 0,

            // Flash Settings
            flash_url: "Scripts/swfupload/swfupload.swf", // Relative to this file
            flash9_url: "Scripts/swfupload/swfupload_FP9.swf", // Relative to this file

            custom_settings: { scope: me },
            // Debug Settings
            debug: false
        });        
    },

以下是swfupload的配置项的说明:

q  upload_url:上传文件的地址,代码中是File控制器的Upload方法。

q  file_size_limit:限制上传文件的大小,代码中限制了只能上传小于10M的文件。

q  file_types:允许上传的文件类型,代码中允许的类型是jpg、png、gif和bmp格式的文件。

q  file_types_description:这个是显示在文件选择对话框中的描述。

q  file_upload_limit:一次允许上传的文件数量,这里设置一次最多只能上传100个文件。

q  file_queue_limit:文件队列的限制,这里设置为0表示没有限制。

q  file_post_name:文件提交后,服务器端可根据该参数获取文件。

q  swfupload_preload_handler:监听预加载事件。

q  swfupload_load_failed_handler:监听上传失败事件。

q  swfupload_loaded_handler:监听上传成功事件。

q  file_queued_handler:监听上传队列事件。

q  file_queue_error_handler:监听队列错误事件。

q  file_dialog_complete_handler:监听文件选择对话框关闭事件。

q  upload_start_handler:监听开始上传事件。

q  upload_progress_handler:监听上传进度事件。

q  upload_error_handler:监听上传错误事件。

q  upload_success_handler:监听上传成功事件。

q  upload_complete_handler:监听上传完成事件。

q  queue_complete_handler:监听上传队列完成事件。

q  button_window_mode:按钮的样式,这里设置了窗口系统模式。

q  button_image_url:按钮图片的路径,因为没有,所以设置了为空。

q  button_placeholder_id:就是SPAN元素的id了。

q  button_width:按钮的宽度,要比TextItem小点。

q  button_height:按钮的高度。

q  button_text:按钮显示的文本,这里要显示的是“上传图片”。

q  button_text_style:按钮文本的样式,这里不需要。

q  button_text_top_padding:按钮文本的顶部内补丁。

q  button_text_left_padding:按钮文本的左边内补丁。

q  flash_url:flash文件所在的路径。

q  flash9_url:flash 9版本的flash文件所在路径。

q  custom_settings:自定义配置,这里一定要添加scope配置项,且值为me,这样就可在swfupload的事件内找到扩展自身,从而使用扩展的属性和方法。

q  debug:是否开启调试模式,false表示不开启。

现在要完成的就是swfupload的监听事件了,这个基本可从swfupload包中的示例代码复制过来,具体代码如下:

    onAfterRender: function(){
        var me = this;

        me.swfu = new SWFUpload({
            upload_url: "/File/Upload",
            file_size_limit: "10 MB",
            file_types: "*.jpg;*.png;*.gif;*.bmp;",
            file_types_description: "图片文件",
            file_upload_limit: 100,
            file_queue_limit: 0,
            file_post_name: "Filedata",

            swfupload_preload_handler: me.UploadPreLoad,
            swfupload_load_failed_handler: me.UploadLoadFailed,
            swfupload_loaded_handler: me.UploadLoaded,
            file_queued_handler: me.fileQueued,
            file_queue_error_handler: me.fileQueueError,
            file_dialog_complete_handler: me.fileDialogComplete,
            upload_start_handler: me.uploadStart,
            upload_progress_handler: me.uploadProgress,
            upload_error_handler: me.uploadError,
            upload_success_handler: me.uploadSuccess,
            upload_complete_handler: me.uploadComplete,
            queue_complete_handler: me.queueComplete,

            // Button settings
            button_window_mode: SWFUpload.WINDOW_MODE.TRANSPARENT,
            button_image_url: '',
            button_placeholder_id: me.spanid,
            button_width: 60,
            button_height: 20,
            button_text: '上传图片',
            button_text_style: '',
            button_text_top_padding: 0,
            button_text_left_padding: 0,

            // Flash Settings
            flash_url: "Scripts/swfupload/swfupload.swf", // Relative to this file
            flash9_url: "Scripts/swfupload/swfupload_FP9.swf", // Relative to this file

            custom_settings: { scope: me },
            // Debug Settings
            debug: false
        });        
    },

    UploadPreLoad: function () {
    },

    UploadLoadFailed: function () {
    },

    UploadLoaded: function () {

    },

    fileQueued: function () {
    },

    fileQueueError: function (file, errorCode, message) {
        try {
            var dlg = Ext.Msg.alert;
            if (errorCode === SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED) {
                dlg("选择的文件太多。\n一次最多上传100个文件,而你选择了" + message + "个文件。");
                return;
            }

            switch (errorCode) {
                case SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT:
                    dlg("文件超过了10M.");
                    this.debug("错误代码: File too big, File name: " + file.name + ", File size: " + file.size + ", Message: " + message);
                    break;
                case SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE:
                    dlg("不允许上传0字节文件。");
                    this.debug("Error Code: Zero byte file, File name: " + file.name + ", File size: " + file.size + ", Message: " + message);
                    break;
                case SWFUpload.QUEUE_ERROR.INVALID_FILETYPE:
                    dlg("非法的文件类型。");
                    this.debug("Error Code: Invalid File Type, File name: " + file.name + ", File size: " + file.size + ", Message: " + message);
                    break;
                default:
                    if (file !== null) {
                        dlg("未知错误。");
                    }
                    this.debug("Error Code: " + errorCode + ", File name: " + file.name + ", File size: " + file.size + ", Message: " + message);
                    break;
            }
        } catch (ex) {
            this.debug(ex);
        }
    },

    fileDialogComplete: function (numFilesSelected, numFilesQueued) {
        try {
            if (numFilesQueued > 0) {
                var me = this.customSettings.scope, sels = me.tree.getSelectionModel().getSelection(), path = "/";
                if (sels.length > 0) {
                    path = sels[0].data.id;
                    SimpleCMS.postParams.path = path;
                    this.setPostParams(SimpleCMS.postParams);
                    this.startUpload();
                }
                else {
                    Ext.Msg.alert("请先选择文件夹。");
                }
            }
        } catch (ex) {
            this.debug(ex);
        }
    },

    uploadStart: function (file) {
        try {
            var me = this.customSettings.scope;
            me.progress.updateProgress(0);
            me.progress.updateText("正在上传文件" + file.name + "...");
        }
        catch (ex) { }

        return true;
    },

    uploadProgress: function (file, bytesLoaded, bytesTotal) {
        try {
            var percent = bytesLoaded / bytesTotal;
            var me = this.customSettings.scope;
            me.progress.updateProgress(percent);
            me.progress.updateText("正在上传文件" + file.name + "...");
        } catch (ex) {
            this.debug(ex);
        }
    },

    uploadError: function (file, errorCode, message) {
        try {
            var me = this.customSettings.scope;
            me.progress.updateText("正在上传文件" + file.name + "...");
            switch (errorCode) {
                case SWFUpload.UPLOAD_ERROR.HTTP_ERROR:
                    me.progress.updateText("上传错误:" + message);
                    this.debug("Error Code: HTTP Error, File name: " + file.name + ", Message: " + message);
                    break;
                case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED:
                    me.progress.updateText("上传失败。");
                    this.debug("Error Code: Upload Failed, File name: " + file.name + ", File size: " + file.size + ", Message: " + message);
                    break;
                case SWFUpload.UPLOAD_ERROR.IO_ERROR:
                    me.progress.updateText("Server (IO) 错误");
                    this.debug("Error Code: IO Error, File name: " + file.name + ", Message: " + message);
                    break;
                case SWFUpload.UPLOAD_ERROR.SECURITY_ERROR:
                    me.progress.updateText("安全错误");
                    this.debug("Error Code: Security Error, File name: " + file.name + ", Message: " + message);
                    break;
                case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:
                    me.progress.updateText("文件大小超出限制。");
                    this.debug("Error Code: Upload Limit Exceeded, File name: " + file.name + ", File size: " + file.size + ", Message: " + message);
                    break;
                case SWFUpload.UPLOAD_ERROR.FILE_VALIDATION_FAILED:
                    me.progress.updateText("验证失败。");
                    this.debug("Error Code: File Validation Failed, File name: " + file.name + ", File size: " + file.size + ", Message: " + message);
                    break;
                case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:
                    break;
                case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:
                    me.progress.updateText("停止");
                    break;
                default:
                    me.progress.updateText("未知错误:" + errorCode);
                    this.debug("Error Code: " + errorCode + ", File name: " + file.name + ", File size: " + file.size + ", Message: " + message);
                    break;
            }
        } catch (ex) {
            this.debug(ex);
        }
    },

    uploadSuccess: function (file, serverData) {
        try {
            var me = this.customSettings.scope;
            me.progress.updateProgress(1);
            me.progress.updateText(serverData);

        } catch (ex) {
            this.debug(ex);
        }
    },

    uploadComplete: function (file) {
        try {
            if (this.getStats().files_queued > 0) {
                this.startUpload();
            } else {
                var me = this.customSettings.scope;
                me.progress.updateProgress(1);
                me.progress.updateText("所有文件已上传。");
                me.filestore.load();
            }
        } catch (ex) {
            this.debug(ex);
        }
    },

    queueComplete: function (numFilesUploaded) {
        var me = this.customSettings.scope;
        me.progress.updateProgress(1);
        me.progress.updateText("已上传" + numFilesUploaded + "个文件");
        if (numFilesUploaded > 0) {
            me.filestore.load();
        }
    }

代码中UploadPreLoad、UploadLoadFailed、UploadLoaded和fileQueued么有使用到,其实可以在配置中去掉,在这里写出来是为了说明一下。要具体了解清楚这些事件,可仔细阅读一下swfupload的API文档。

先来看看fileQueueError方法,该方法会在队列出现出错时触发。代码中,涉及dlg的代码是提示给用户看的,debug则是在开启了调试模式时使用的。

方法fileDialogComplete会在文件选择对话框关闭后触发,在这里就意味着开始上传文件了,因而,当检测到队列中有文件(numFilesQueued大于0),就从customSettings中获取扩展自身,然后从树中获取选择模型,看是否有选择节点,如果有,就把选择节点(目录)作为上传路径,否则,提示用户选择一个节点(目录)。

在这里一定会很奇怪,为什么会有一个ExtMVCOne. postParams的东西,它有什么用?这主要是验证问题,因为Flash上传并不会把当前页面的验证作为其验证,因而要在服务器端验证上传文件的用户是否已经登录且符合权限要求,就要求通过添加验证方式办法来实现,它的具体代码如下:

                ExtMVCOne.postParams = {
                    path: null,
                    "ASPSESSID": "@Session.SessionID",
                    "AUTHID": "@Request.Cookies[FormsAuthentication.FormsCookieName].Value"
                };

代码中,path是用来设置上传路径的,后面两项就是用来填写验证信息用的。笔者在第一次做这个的时候,上传老是不成功,然后在调试模式下(设置debug为true),看到的提示是权限不足,奇怪了,然后google一下,发现原来Flash上传文件的验证信息不能和页面的同步,要加这两个东西来实现。

要完成这个,还要打开Global.asax文件,在里面加入以下代码:

        protected void Application_BeginRequest()
        {
            var Request = HttpContext.Current.Request;
            var Response = HttpContext.Current.Response;

            try
            {
                string session_param_name = "ASPSESSID";
                string session_cookie_name = "ASP.NET_SESSIONID";

                if (HttpContext.Current.Request.Form[session_param_name] != null)
                {
                    UpdateCookie(session_cookie_name, HttpContext.Current.Request.Form[session_param_name]);
                }
                else if (HttpContext.Current.Request.QueryString[session_param_name] != null)
                {
                    UpdateCookie(session_cookie_name, HttpContext.Current.Request.QueryString[session_param_name]);
                }

                string auth_param_name = "AUTHID";
                string auth_cookie_name = FormsAuthentication.FormsCookieName;

                if (HttpContext.Current.Request.Form[auth_param_name] != null)
                {
                    UpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[auth_param_name]);
                }
                else if (HttpContext.Current.Request.QueryString[auth_param_name] != null)
                {
                    UpdateCookie(auth_cookie_name, HttpContext.Current.Request.QueryString[auth_param_name]);
                }
            }
            catch (Exception e)
            {
                Response.StatusCode = 500;
                Response.Write("Error Initializing Session");
            }
        }

        private static void UpdateCookie(string cookie_name, string cookie_value)
        {
            HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookie_name);
            if (cookie == null)
            {
                cookie = new HttpCookie(cookie_name);
                //SWFUpload 的Demo中给的代码有问题,需要加上cookie.Expires 设置才可以
                cookie.Expires = DateTime.Now.AddYears(1);
                HttpContext.Current.Request.Cookies.Add(cookie);
            }
            cookie.Value = cookie_value;
            HttpContext.Current.Request.Cookies.Set(cookie);
        }

其实这代码,在swfupload的示例中也是有的,只是笔者没留意。

回到fileDialogComplete方法,调用swfupload的setPostParams方法就可将参数复制到swfupload中了,然后调用startUpload方法就可以开始上传文件了。

方法uploadStart会在文件开始上传的时候执行,在这里要做的就是更新进度条了。(这里说明一下,swfupload是一个个文件传的,并不是一次把所有文件都传过去的)。

方法uploadProgress就是用来更新进度的,主要功能就是更新进度条了。

方法uploadError是用来显示上传错误的,复制过来根据自己想法修改提示方式就行了。

方法uploadSuccess会在一个文件上传成功后执行,这里要做的就是将进度条显示到100%,并显示服务器端返回的信息。

文件上传完也会执行uploadComplete方法,在这里可检查队列中是是否还有文件,如果有,就调用startUpload继续上传,如果没有,则更新进度条显示,说明文件已经全部上传完毕。

队列中的文件都上传后会执行queueComplete方法,这个和uploadComplete方法检查队列中没有文件后的处理有点重叠,看你怎么取舍了。

最后,别忘了在Index.html加入加载swfupload.js的代码,代码如下:

    @if (Request.IsAuthenticated)
    {
       <script type="text/javascript"src="@Url.Content("Scripts/swfupload/swfupload.js")"></script>
    }

这个脚本只有在登录后才会加载。

现在切换到File控制器,完成Upload方法,这个不难,就是接收一个文件,然后保存而已,代码如下:

public string Upload()
        {
            string path = Request["path"] ?? "";
            string[] filetypes = { "jpg", "gif", "png", "bmp" };
            string dir = Server.MapPath(root + path);
            if (Directory.Exists(dir))
            {
                HttpPostedFileBase file = Request.Files["Filedata"];
                string filename = file.FileName.ToLower();
                string extname = filename.Substring(filename.LastIndexOf(".") + 1, 3);
                if (file.ContentLength <= 0)
                {
                    return "不允许上传0字节文件。";
                }
                else if (file.ContentLength > 10485760)
                {
                    return "文件超过了10M。";
                }
                else if (!filetypes.Contains(extname))
                {
                    return "文件类型错误。" + extname;
                }
                else
                {
                    try
                    {
                        file.SaveAs(dir + "\\" + filename);
                        return "文件已上传。" + dir + "\\" + filename;
                    }
                    catch (Exception e)
                    {
                        return e.Message;
                    }
                }
            }
            else
            {
                return "保存目录不存在或已被删除。";
            }

        }

上传功能暂时告一段落,有待优化。

 示例代码下载链接http://url.cn/GyJnDK

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PIC CMS图片网站管理系统程序介绍 基于更成熟的PHP应用框架和设计理念,全新的控制器,模型以及核心类库;优化了多级分类的结构,增加了全站生成静态页面,负载和SEO方面都全面加强;内置了采集接口(Beta),以后还会增加对其它外部采集器的支持;前后端界面也全面重构,更加简洁,规范和易用。开放全部源代码,并保留所有注释,可以在遵循开源协议的前提下,方便的进行二次开发,甚至可以基于术框架构架一个全新的系统,我们将来会提供详细的API文档。 1.最快捷,最方便的图片上传和管理系统 2.采用MVC架构,详尽注释,方便二次开发和扩展 3.UTF-8编码,方便安装在国外主机 4.支持批量上传,抓取远程图片 5.外部图片自动保存在本地 6.自动控制上传图片和本地化图片尺寸 7.自动给上传及本地化图片添加水印 8.自动提取首张图片为缩略图 9.自动生成任意大小缩略图 10.幻灯片模式图片展示页 11.支持静态缓存,全站生成HTML 12.内置采集器,迅速从网络抓取图文 13.自由分类,自动生成导航和内容调用 14.模板分离设计,轻松设计模板 15方便自由的模板方法,可以实现复杂多样的调用效果 1.1版本升级为1.2数据库升级请依此按照下面四部进行(SQL运行器直接运行下面4句SQL,分四次,不能一次进行,去掉前面1-4序列号): 1:ALTER TABLE `pc_article` ADD `xiazai` VARCHAR(800) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' AFTER `jumpurl`; 2:ALTER TABLE `pc_article` ADD `mima` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `xiazai`; 3:ALTER TABLE `pc_article` ADD `wangpan` VARCHAR(800) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' AFTER `mima`; 4:ALTER TABLE `pc_article` ADD `tiquma` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER `wangpan`; 开发团队情况: PICCMS开发团队成立于2015年12月1日,是由青岛网众文化传媒有限公司互联网技术服务中心投资并牵头组建的专业PHP网站应用程序开发团队。团队现有网站美工3人,PHP开发工程师3人,网站运行测试师2名,项目经理1名,行政文秘2名。PICCMS开发团队旨在延续PICCMS系统的精髓,在原有PICCMS基础上继续开发专业的图片网站管理系统,为追随者和支持者提供最好的图片类网站解决方案。 有品味的PHP开发团队 PICCMS开发团队是一代真正有品味、有观点、有个性、爱生活的PHP开发团队。PICCMS开发团队把彰显个性品味的设计与超强性能的融合放在首位,旨在为广大图片类网站站长提供最专业的图片网站管理系统与服务。我们来自互联网,也将永远为互联网发展和进步拼搏,我们不懂得运营与盈利,但是我们确实懂PHP技术(我们依然要学习),可以提供高标准的技术服务和安全高效的产品,希望我们的努力能为您提供一个高效快速和强大的图片网站解决方案。 最纯粹的PHP开发团队 原PicCMS图片管理系统是原PicCMS开发团队在2012年开发之作(MyPic开发团队三年后回归之作),但是不幸的是原PicCMS开发团队在发布V1.1之后在此销声匿迹,如同当年的MYPIC一样,短暂的璀璨却留下了无限的期盼、遗憾和痛心。为了弥补PHP开发开源界图片网站管理系统的空缺,由青岛网众文化传媒有限公司互联网技术服务中心投资并牵头,在众多PICCMS的追随者的支持下,新的PICCMS开发团队2015年12月1日正式成立,宣誓延续原PICCMS精髓的同时,保证依然贯彻永久全部开源、免费的理念,坚定不移的继续研发,为广大图片类网站提供高效快速和强大的图片网站解决方案。 新PICCMS是一个完全意义上的图片网站管理系统品牌,新PICCMS开发团队也将围绕PICCMS图片网站管理系统开展仿站业务、模板设计、程序定制、源码修改等全方位的网站开发服务。 期待英雄的回归 新PICCMS开发团队是稚嫩的婴儿,需要不断的学习才能茁壮成长,这个过程注定非常漫长和痛苦,所以我们真心的期盼原PICCMS(MYPIC)开发团队的回归或者给我们提供帮

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值