Extjs3 + swfUpload实现多文件上传控件

要在ExrtJS框架实现选择多文件上传,FileUploadField已经无法满足需求,所以采用了 swfUpload上传控件,上传窗口如下:

多选文件进行上传(其实是每个文件异步上传),可以中途停止文件上传,移除所选文件等操作。上传窗口代码如下:


var ctx = '<%=request.getContextPath()%>';
Ext.onReady(function(){
    Ext.QuickTips.init();
    new Ext.Window({
        width : 650,
        title : '选择目标文件上传',
        height : 300,
        layout : 'fit',
        items : [
            {
                xtype:'uploadPanel',
                border : false,
                fileSize : 1024*50,//限制文件大小kb
                uploadUrl : ctx+'/uploadFiles.action',
                flashUrl : ctx+'/swfupload.swf',//flash文件路径
                filePostName : 'file', //后台接收参数名称
                fileTypes : '*.*',//可上传文件类型 *.doc
                postParams : {savePath:'upload'} //需要传到后台的参数
            }
        ]
    }).show();
});

构建完列表后 afterrender 监听函数添加flash生成文件选择窗口:

keel.UploadPanel.superclass.constructor.call(this,{                
        tbar : [
            {text:'添加文件',iconCls:'add',ref:'../addBtn'},'->',
            {text:'上传',ref:'../uploadBtn',iconCls:'up',handler:this.startUpload,scope:this},'-',
            {text:'停止上传',ref:'../stopBtn',iconCls:'delete',handler:this.stopUpload,scope:this,disabled:true},'-',
            {text:'移除所有',ref:'../deleteBtn',iconCls:'delete2',handler:this.deleteAll,scope:this},'-'
        ],
        layout : 'fit',
        items : [this.gp],
        listeners : {
            'afterrender':function(){
                var em = this.getTopToolbar().get(0).el.child('em');
                var placeHolderId = Ext.id();
                em.setStyle({
                    position : 'relative',
                    display : 'block'
                });
                em.createChild({
                    tag : 'div',
                    id : placeHolderId
                });
                this.swfupload = new SWFUpload(Ext.apply(this.setting,{
                    button_width : em.getWidth(),
                    button_height : em.getHeight(),
                    button_placeholder_id :placeHolderId
                }));
                this.swfupload.uploadStopped = false;
                Ext.get(this.swfupload.movieName).setStyle({
                    position : 'absolute',
                    top : 0,
                    left : -2//此处需设置为0,否则flash偏右按钮失效
                });                
            },
            scope : this,
            delay : 100
        }
    });

后台uploadFiles.action上传成功{"success":true},上传失败返回{"success":false},前台接收进行处理:

//文件上传成功后触发的事件处理函数 
onUploadSuccess : function(file, serverData) { var me
= this.customSettings.scope_handler; var ds = me.gp.store; if (Ext.util.JSON.decode(serverData).success) { for(var i=0;i<ds.getCount();i++){ var rec =ds.getAt(i); if(rec.get('id')==file.id){ rec.set('state', file.filestatus); rec.commit(); } } }else{ for(var i=0;i<ds.getCount();i++){ var rec =ds.getAt(i); if(rec.get('id')==file.id){ rec.set('percent', 0); rec.set('state', -3); rec.commit(); } } } me.linkBtnEvent(); }

index.jsp 页面代码如下:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>    
    <title>swfUpload demo</title>
    <link rel="stylesheet" href="<%=request.getContextPath()%>/public/css/common.css" type="text/css" />
    <script type='text/javascript' src="<%=request.getContextPath()%>/public/ext/ext-base.js"></script>
    <script type='text/javascript' src="<%=request.getContextPath()%>/public/ext/ext-all.js"></script>
    <script type="text/javascript" src="<%=request.getContextPath()%>/public/ux/uploader/swfupload.js"></script>
    <script type="text/javascript" src="<%=request.getContextPath()%>/public/ux/uploader/uploaderPanel.js"></script>
  </head>
  
  <body>
  </body>
</html>

衷心感谢博主: http://czpae86.iteye.com/blog/834123?page=2#comments

-------------------------------------------------华丽丽的分割线----------------------------------------------

满心欢喜的提交了代码,但测试那边同事反馈火狐浏览器无法上传,经过查找网上很多人遇到这种情况,原来是FireFox下使用swfUpload flash上传文件session丢失这个bug。由于项目后台做了登录用户权限控制,点击上传的时候验证未通过请求被抛弃,所以文件上传失败。

网上技术大拿有如下文章:

当页面需要使用 session 中的用户信息时,却无法在 Firefox 下使用它进行正常的文件上传。在 IE 下,上传工具能够工作,而一到 Firefox 下,SWFUpload 就会提示错误 302。通过从 Fiddler 抓包,发现上传文件的请求被 302 重定向到了登陆页面,所以无法正常上传文件。也就是说,之前用户登陆后的 session 信息在 Flash 发送的上传请求中丢失了。再一看请求的 header,当中没有可以用来标识当前 session ID 的 cookie 值(对于 J2EE 为 JSESSIONID,PHP 为 PHPSESSID 等)。这是什么原因呢?经过一番搜索,找到了 Adobe 官方的一篇文章,说道:

A FileReference.upload() currently does not use the same cookies as your browser session if you are using Firefox (on Windows). In such cases, cookie information has to be inserted manually. 

好吧,这个解释虽然很清楚地表明,Flash 在 Firefox 下进行文件上传不会使用浏览器 cookie 中的 session ID,但是貌似并没有回答文章标题当中的“为什么”,即为什么不使用和浏览器中的 session ID 来进行通信。

看来 cookie 是指望不上了,那只能像上面说的那样“手工”传递 session ID 了。于是我们可以在 URL 中拼接一个如 ";jsessionid=blahblah" 的字符串(注意要拼在路径之后,参数之前),像下面这样:

uploadUrl : 'http://example.com/app;jsessionid=blahblah'

Servlet 规范 7.1.3 节中的规定,当客户端不接受 cookie 时,Servlet 容器应当能解析出这类 URL 中的 JSESSIONID,来维持当前 session 的状态。其他服务器端环境中也有类似的机制。于是我们对文件上传功能做了一定的修改:在用户进入上传页面时,就把当前的 session ID 写到页面中,作为 JavaScript 变量拼接到 SWFUpload 上传文件的目标 URL 中,Flash 就可以利用我们人工传入的 JSESSIONID 来维持登陆状态了。当开始上传时,Flash 通过自己的连接通道向服务器发送数据,但是因为请求的路径中包含了 session 信息所以可以和浏览器的 session 状态保持同步,服务器可以通过 URL 中的 session ID 来获取用户登录的信息。

于是,302 错误被解决了,看起来一切都 OK 了。可是,不久我们又发现了新的问题:当用户打开上传页面后较长时间没有操作,服务器端的 session 超时了,这个时候进行文件的上传用的还是超时的那个 session ID,所以会失败也是应该的。但是当这个时候用户重新进行了登录,再次进入上传页面上传,却仍然会失败,只有重新启动浏览器才能再次进行上传。这是为什么 呢?从服务器端错误来看,还是用户的登陆信息丢失的问题,也就是说,Flash 在上传文件时,还是没能将用户进行过登陆的这个 session ID 成功传递给服务器端。通过在 Fiddler 中抓包分析,终于找到了原因。

文章来源 http://lync.in/session-trap-on-uploading-files-using-flash-in-firefox/

这个方法可以解决大部分网友遇到seesion丢失的问题,但我的项目里调用的是jsf的统一登录接口,没有得到产生的一级域名cookie,按照这种解决方式上传请求还是会被抛弃,焦头烂额的搞了几个小时,突然想到让上传的方法不被Interceptor拦截不就解决了吗,山重水复疑无路,最后在拦截器配置文件里修改一下:

exclude.path=/common/uploadFiles.do,/common/uploadImgs.do

经过这样的一个过程基本上实现了多文件上传的功能,适用于后台上传文件的代码没有用到seesion这情况。

原文地址:https://www.cnblogs.com/yzuzhang/p/5127345.html