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

时间:2022-08-30 09:52:26

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

Extjs3 + 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这情况。