标签:
最近项目中要求使用HTTP做文件上传,而且要求有进度显示,在网上东找西寻了半天,解决方案倒也不少,比如使用Ajax上传,但感觉这种方式的进度提示 太麻烦,所以没有采用,后来看到了SWFUpload,就找了些资料来看,觉得符合自己的要求,研究了足有两天,略有心得,忙不迭地记录下来,以防止时间 长了遗忘,如果不小心帮助了别人,那就更好了,呵呵...
下面摘抄一段SWFUpload官网的介绍(别人翻译过来的):
SWFUpload 最初是由Vinterwebb.se 开发的客户端文件上传工具。它结合javascript和flash在浏览器中提供一个优于传统上传标签 <input type="file" /> 的功能(和良好的用户体验)。
SWFUpload 的主要特性:
SWFUpload 的设计理念与其他基于flash的上传工具不同。SWFUpload 给开发者尽可能多的UI控制能力. 开发者可以使用
XHTML, CSS, JavaScript 来使它更符合自己网站的样式风格.
它提供一组简单的js事件更新上传状态,开发者可以根据这些事件来在网页中显示文件上传进度
好了,夸奖的话不多说了,既然它这么受欢迎,想必是有一定优势的。
下面记录一下我做的一个小示例,先预览一下程序运行效果:
有朋友索要例子源码,其实我早已放在我的资源里了,并没有设置下载积分,有需要的朋友请到这里下载:http://download.csdn.net/detail/zhangyihui1986/4538748
现在SWFUpload项目托管于Google code下,URL为:http://code.google.com/p/swfupload/ ,请自行下载,下载的压缩文件中含有一个文档,里面详细介绍了SWFUpload的配置参数、事件支持、支持方法等。
这里是官网上的几个例子:http://demo.swfupload.org/
网络上关于SWFUpload的博客资源很多,但很多博客质量不太高,而且转来转去,内容重复,所以我在查资料的时候没有找到太合适的资源,后来找到了这里:http://webdeveloperplus.com/jquery/multiple-file-upload-with-progress-bar-using-jquery/ ,这是一个外国人写的关于SWFUpload的小教程,UI做地也挺好,于是我就参照着做了个小例子。
不过,上面链接的教程是针对SWFUpload一个针对JQuery的插件写的,这个插件地址为:http://blogs.bigfish.tv/adam/2009/06/14/swfupload-jquery-plugin/,该插件好像仅仅是完善了一下SWFUpload的事件机制,使用它可采用JQuery的链式写法,但我没有用它,而是用的原生的SWFUpload2.2版本。
不多说,先贴出来我做的例子,然后再针对代码作适当解释。
例子使用了Struts2.3.4作为后台,当然,SWFUpload是不选择后台的,您可以使用任意的技术,只要是能实现HTTP协议即可。
1)将下载的压缩文件解压并拷到web项目中(此处我放到项目的js目录下),建立其它资源(如JSP、Action等)后目录结构如下图所示:
2)在JSP文件中引入SWFUpload依赖的JS文件
在此处我用到了ligerUI框架,如果不使用它,那么仅需要引jquery和swfupload.js两个文件即可。
3)JSP文件中HTML结构
4)JSP文件中CSS,给文件上传进度列表赋与样式,我对CSS不够熟悉,此处的样式几乎全部来自于前面那个教程,仅作了一些小的变动。如果您觉得这还不够好,那您自己来实现漂亮的UI界面吧!
5)JSP中的Javascript,主要是创建SWFUpload组件实例,并绑定监听函数,在监听函数中处理进度提示:
SWFUpload组件的实例化很简单,就是new一个JS对象,如
我们需要传给它一个配置对象,这个配置对象的内容很多,详细介绍请参照使用说明文档,在此仅介绍几个重要一些的配置参数,以注释的形式写在代码里。
需要注意的是按钮的高和宽一定要指定,否则flash无法显示。
swfupload仅实现了后台操作,前台的处理空间留给了开发者,它采用事件触发机制,让开发者捕获特定事件,自定义对应的事件处理函数进行相应处理。 即当swfupload内部某一特定事件发生,便触发相应的JS函数,并传入合适的相关参数,开发者就可以拿着这些参数来更新UI界面以提示上传进度了。 Swfupload通过固定的事件函数名属性值寻找自定义的JS函数,所以在初始化工作中,将自定义的JS函数名赋值给swfupload指定的对应属性 即可。
默认情况下,你选择了文件并关闭了文件选择对话框文件并不会自动开始上传,你需要调用SWFUpload的startUpload()方法,该方法接收一个file_id作为参数,如果参数为空,则自动开始上传文件队列中的第一个文件。
另外,在所有的事件监听器中,this关键字都是指向SWFUpload对象,所以你可以在file_queued_handler或file_dialog_complete_handler等事件监听器中这样开始文件上传:
默认情况下,你在第3步中开始了一个文件上传,但是如果你选择的是多个文件,那么你会发现这个文件上传后其它文件并不会自动开始上传,这是为什么呢?原来 Swfupload虽支持批量上传,但本质仍是单个文件依次上传,所以如果你的上传是支持多个文件上传那只有你自己去开始其它文件的自动上传了,我们可以 在upload_complete_handler事件监听器中再调用一个startUpload()方法:
因为upload_complete_handler事件是在一个文件上传后触发,不管该文件是否上传成功都会触发该事件,所以我们在这里再调用一次startUpload方法是合适的,这样SWFUpload组件在前一个文件上传完成后就会自动开始下一个文件的上传。
显示出上传文件进度列表能够增强用户体验,因为用户将看见选择的文件信息以及该文件的上传进度,这些东西就完全由开者来定制了,SWFUpload组件将 丰富的文件信息及上传进度在调用事件监听函数时以参数的形式传进来,我们就可以利用这些信息动态更新文件上传进度UI了。如前面的例子我们在 file_queued_handler事件监听函数中将文件信息及其进度条拼接到页面的ol列表中,在upload_start_handler事件监 听函数中初始化进度条显示,然后在文件上传过程中会不停地触发upload_progress_handler事件,我们就在这个事件监听函数中获取上传 进度,并将其更新到进度列表,这样便可实现文件上传的进度提示。在SWFUpload丰富的事件机制支持下,实现这些东西是很容易的事。
在SWFUpload的配置参数中有一个post_params参数是用来向后台传递参数的,默认情况好像是不能传递参数的,但是如果你将另一个配置参数use_query_string设置为true之后就可以传递参数了。
该参数接收一个JS对象,类似于这样:
但是如果参数值中含有中文的话,那么后台会报错,也取不到值,可以这样解决:
在JS中先用UTF-8进行中文编码
然后在后台再转回来,在Java中就体现为
如此便可解决中文参数传递问题。
假设有这种需求:文件上传完成后跳转到指定的页面,比如文件信息查看页面,那我们可能会一时找不到好的方法,因为SWFUpload上传类似于Ajax上 传,涉及到的上传交互操作并非是浏览器所发,而是由Flash发出的上传请求,那么后台给出的跳转信息浏览器自然接收不到,而是由Flash接收到了,既 然浏览器接收不到跳转信息,那么自动跳转就不会发生。
对于这种需求,我们可以参照Ajax提交跳转的方式,在后台成功接收文件后输出一些信息,比如跳转的页面,或者仅仅是一个字符串,而把跳转的任务交由 Javascript来完成,那么我们应该在什么事件监听函数中处理呢!您可以看看upload_success_handler这个事件的回调函数有什 么参数,如下:
这个事件发生后会传三个参数到我们定义的监听函数中,第一个是上传完成的文件对象(关于文件对象可参看SWFUpload的文档,其实就是一个JS对象, 包含一些重要的文件信息),第二个其实是服务器返回的数据,如果后台用的直接跳转,那么这里的server data就会是跳转页面的HTML结构,document.write()将其输出,也算是完成跳转了吧!如果你仅仅是向前台输出个字符串,并没有跳转, 那么这里就应该是你输出的字符串,在这里就可以用location.href=“来实现跳转;第三个参数是Boolean类型,表示是否接收到服务器传回 的数据。
需要注意的是该事件在每个文件上传成功均会触发,如果同时在上传多个文件,那么第一个文件上传完成后页面就直接跳转了,后台的文件也就得不到机会上传了, 所以这里需要判断一下队列里是否还有没有上传完成的文件,如果没有了再跳转,就可以了,至于如何判断队列里是否还有未上传的文件,这里用到了 SWFUpload的另一个对象Stats。该对象提供了上传队列的状态信息,访问实例的getStats方法可获取此对象,该对象中有一些属性,其中有 一个files_queued属性可以表示是否还有未上传的文件,如果该属性为0则表示全部上传,可以这样做
最近在使用SWFUpload过程中发现一个问题,文件上传成功后我需要将其移动到指定目录下,由于目录信息是在Session中的,这时在非IE浏览器 中出现了问题,Session中没有东西,用户登录信息也没有了。经过调试才发现文件上传成功后在后台取到的Session与用户登录完成后的 Session相比根本就不是一个Session了,它们的ID不同,也就是说文件上传另生成了一个Session,而这个Session是全新的,当然 没有了登录时存放的信息了。
经过一番搜索,这是由于Flash Player在非IE浏览器下一个Bug引起的,这里有一段描述:
Cookie issue
On Windows the Non-IE Flash Player plugin (FireFox, Opera, Safari, etc) sends the IE cookies regardless of the browser used. This breaks authentication and sessions for many server-side scripting technologies.
Developers should manually pass Session and Authentication cookie information and manually restore Sessions on the Server Side if they wish to use Sessions
The SWFUpload package contains work-around sample code for PHP and ASP.Net
也就是说非IE浏览器下Flash Player插件发送的也是IE浏览器当前页面的cookie,并且Session是靠Cookie中保存的SessionId实现的,因此后台处理程序另新建了Session,程序也就出现了上述错误。
找到的解决办法是手动将SessionID传到后台服务端。
在上传路径URL里加上jsessionid变量即可,如下:
这样就可以解决问题了,有人还说可以使用SWFUpload组件的一个插件:swfupload.cookies.js,但我没有弄好,看它的源码是分 析浏览器的cookie然后将它们拼接到post_params配置项中,我手动拼上jsessionid也是不起作用,不知道是不是自己没弄对,反正是 这个插件我没有成功使用。
标签:
原文地址:http://www.cnblogs.com/donchen/p/4648794.html