zoukankan      html  css  js  c++  java
  • 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这情况。

  • 相关阅读:
    Java打jar包详解
    用户体验评价
    本周总结(13)
    本周总结(12)
    第一阶段意见评论
    本周总结(11)
    冲刺计划第十天
    冲刺计划第九天
    冲刺计划第八天
    冲刺计划第七天
  • 原文地址:https://www.cnblogs.com/yzuzhang/p/5127345.html
Copyright © 2011-2022 走看看