要在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这情况。