Stream 上传插件

Stream 是解决不同浏览器上传文件的插件,是Uploadify的Flash版和Html5版的结合!

Stream 简介

Stream 是根据某网的文件上传插件加工而来,支持不同平台(Windows, Linux, Mac, Android, iOS)下,主流浏览器(IE7+, Chrome, Firefox, Safari, 其他)的上传工作,当然在Html5标准下,还支持文件的断点续传功能,有效解决大文件的Web上传问题!

主要特征

1. 源码完全开放,目前有Java、PHP、Perl三种后台语言实现

2. 支持HTML5、Flash两种方式(跨域)上传

3. 多文件一起上传

4. HTML5支持断点续传,拖拽等新特性

5. 兼容性好IE7+, FF3.6+, Chrome*,Safari4+,遨游等主流浏览器

6. 进度条、速度、剩余时间等附属信息

7. `选择文件的按钮`可以自定义

8. 简单的参数配置实现 灵活多变的功能

9. 支持文件夹上传(Chrome21+, Opera15+)

10. 支持自定义UI(V1.4+)

(最近修改: 2015-08-17) ©2015 Twinkling.cn

强制Form表单上传

演示地址:http://p.twinkling.cn/force-form.html

又拍云表单上传

演示地址:http://p.twinkling.cn/upyun-form.html

Dropzonejs样式

演示地址:http://p.twinkling.cn/dropzone.html

自定义UI

演示地址:http://p.twinkling.cn/bootstrap.html

断点续传(Firefox4+, Chrome, Safari6+, IE10+)

演示地址:http://p.twinkling.cn/

单个文件

演示地址:http://p.twinkling.cn/s1.html

启动参数:

							    	var config = {
											maxSize: 10485760 /** 单个文件的最大大小,默认:2G */
											tokenURL : "/tk", /** 根据文件名、大小等信息获取Token的URI(用于生成断点续传、跨域的令牌) */
											frmUploadURL : "/fd;", /** Flash上传的URI */
											uploadURL : "/upload", /** HTML5上传的URI */
										};
									new Stream(config);

多个文件

演示地址:http://p.twinkling.cn/s2.html

启动参数:

							    	var config = {
											multipleFiles: true, /** 多个文件一起上传, 默认: false */
											maxSize: 10485760 /** 单个文件的最大大小,默认:2G */
											tokenURL : "/tk", /** 根据文件名、大小等信息获取Token的URI(用于生成断点续传、跨域的令牌) */
											frmUploadURL : "/fd;", /** Flash上传的URI */
											uploadURL : "/upload", /** HTML5上传的URI */
										};
									new Stream(config);

跨域上传文件

演示地址:http://p.twinkling.cn/s3.html

启动参数:

							    	var config = {
											multipleFiles: true, /** 多个文件一起上传, 默认: false */
											maxSize: 10485760 /** 单个文件的最大大小,默认:2G */
											tokenURL : "/tk", /** 根据文件名、大小等信息获取Token的URI(用于生成断点续传、跨域的令牌) */
											frmUploadURL : "http://cross.twinkling.cn/fd;", /** Flash上传的URI */
											uploadURL : "http://cross.twinkling.cn/upload", /** HTML5上传的URI */
										};
									new Stream(config);
或者:
							    	var config = {
											multipleFiles: true, /** 多个文件一起上传, 默认: false */
											maxSize: 10485760 /** 单个文件的最大大小,默认:2G */
											tokenURL : "/tk", /** 根据文件名、大小等信息获取Token的URI(用于生成断点续传、跨域的令牌) */
											frmUploadURL : "/fd;", /** Flash上传的URI */
											uploadURL : "/upload", /** HTML5上传的URI */
										};
									new Stream(config);
									
									在调用/tk的时候,返回{"message":"","token":"A543080287_4176","server":"http://cross.twinkling.cn","success":true}
									这个返回结果比正常多了个server字段,即指定
									frmUploadURL : "http://cross.twinkling.cn/fd;", /** Flash上传的URI */
									uploadURL : "http://cross.twinkling.cn/upload", /** HTML5上传的URI */

响应函数示例

演示地址:http://p.twinkling.cn/s4.html

启动参数:

							    	var config = {
											multipleFiles: true, /** 多个文件一起上传, 默认: false */
											maxSize: 10485760 /** 单个文件的最大大小,默认:2G */
											tokenURL : "/tk", /** 根据文件名、大小等信息获取Token的URI(用于生成断点续传、跨域的令牌) */
											frmUploadURL : "/fd;", /** Flash上传的URI */
											uploadURL : "/upload", /** HTML5上传的URI */
											onSelect: function(files) {alert('onSelect')}, /** 选择文件后的响应事件 */
											onMaxSizeExceed: function(file) {alert('onMaxSizeExceed')}, /** 文件大小超出的响应事件 */
											onFileCountExceed: function(selected, limit) {alert('onFileCountExceed')}, /** 文件数量超出的响应事件 */
											onExtNameMismatch: function(file) {alert('onExtNameMismatch')}, /** 文件的扩展名不匹配的响应事件 */
											onCancel : function(file) {alert('Canceled:  ' + file.name)}, /** 取消上传文件的响应事件 */
											onComplete: function(file) {alert('onComplete')}, /** 单个文件上传完毕的响应事件 */
											onQueueComplete: function(msg) {alert('onQueueComplete')}, /** 所以文件上传完毕的响应事件 */
											onUploadError: function(status, msg) {alert('onUploadError')} /** 文件上传出错的响应事件 */
										};
									new Stream(config);

全部自定义参数

演示地址:http://p.twinkling.cn/s5.html

启动参数:

							    	var config = {
											multipleFiles: true, /** 多个文件一起上传, 默认: false */
											maxSize: 10485760 /** 单个文件的最大大小,默认:2G */
											retryCount : 5, /** HTML5上传失败的重试次数 */
											postVarsPerFile : { /** 上传文件时传入的参数,默认: {} */
												param1: "val1",
												param2: "val2"
											},
											swfURL : "/swf/FlashUploader.swf", /** SWF文件的位置 */
											tokenURL : "/tk", /** 根据文件名、大小等信息获取Token的URI(用于生成断点续传、跨域的令牌) */
											frmUploadURL : "/fd;", /** Flash上传的URI */
											uploadURL : "/upload", /** HTML5上传的URI */
											simLimit: 100, /** 单次最大上传文件个数 */
											extFilters: [".txt", ".rpm", ".rmvb", ".gz", ".rar", ".zip", ".avi", ".mkv", ".mp3"], /** 允许的文件扩展名, 默认: [],即全部允许 */
											onSelect: function(files) {alert('onSelect')}, /** 选择文件后的响应事件 */
											onMaxSizeExceed: function(file) {alert('onMaxSizeExceed')}, /** 文件大小超出的响应事件 */
											onFileCountExceed: function(selected, limit) {alert('onFileCountExceed')}, /** 文件数量超出的响应事件 */
											onExtNameMismatch: function(file) {alert('onExtNameMismatch')}, /** 文件的扩展名不匹配的响应事件 */
											onCancel : function(file) {alert('Canceled:  ' + file.name)}, /** 取消上传文件的响应事件 */
											onComplete: function(file) {alert('onComplete')}, /** 单个文件上传完毕的响应事件 */
											onQueueComplete: function(msg) {alert('onQueueComplete')}, /** 所有文件上传完毕的响应事件 */
											onUploadError: function(status, msg) {alert('onUploadError')} /** 文件上传出错的响应事件 */
										};
									new Stream(config);

参数

属性名 说明 参数类型 示例 默认值
multipleFiles 是否允许同时选择多个文件 boolean true false
formed 强制表单上传 boolean true false
customered 是否是自定义UI boolean true false
autoUploading 选择文件后是否自动上传 boolean false true
autoRemoveCompleted 文件上传后是否移除(customered=false时有效) boolean true false
maxSize 单个文件的大小限制,单位:字节 int 2147483648 默认是2G,即2147483648
browseFileId 文件选择DIV的ID String i_select_files i_select_files
browser 文件选择DIV的DOM元素(jQuery对象请转换成正常的Dom元素,若browser不为空,browseFileId设置项是会被忽略的) Dom document.getElementByName("Browser")[0]
dragAndDropArea 拖拽上传区域的ID(为null时,表示禁用拖拽上传功能) String i_stream_dropzone (null)
browseFileBtn `文件选择`按钮的样式(customered=false时有效) String 请选择文件
请选择文件
filesQueueId 文件显示容器的ID(customered=false时有效) String i_stream_files_queue i_stream_files_queue
filesQueueHeight 文件上传显示容器的高度(customered=false时有效) int 200 450
messagerId 显示消息元素ID(customered=false时有效) String i_stream_message_container i_stream_message_container
retryCount HTML5上传失败的重试次数 int 8 5
postVarsPerFile 上传文件时传入的参数 {} {param1: "val1", param2: "val2"}
swfURL SWF文件的位置 String http://s1.twinkling.cn//swf/FlashUploader.swf /swf/FlashUploader.swf
tokenURL 根据文件名、大小等信息获取Token的URI(用于生成断点续传、跨域的令牌) String /tk /tk
frmUploadURL Flash上传的URI String /fd /fd
uploadURL HTML5上传的URI String /upload /upload
simLimit 单次最大上传文件个数 int 10000 100
extFilters 允许上传文件的类型 [] [".txt", ".rpm"] 默认全部允许

 

事件

响应事件 说明 参数 备注
onSelect 选择文件后的响应事件
								      onSelect: function(list) {
								      	console.log("select files: " + list.length);
								      	for (var i=0; i < list.length; i++) {
								      		console.log("file name: "
								      		 + list[i].name
								      		 + " file size:"
								      		 + list[i].size);
								      	}
								      }
								      	/**
								      	 * @list 文件列表, 由json元素组成的数组
								      	 *  {
								      	 *    id: "",
								      	 *    name: "",
								      	 *    size: ""
								      	 *  }
								      	 */
								      	onSelect: function(list);
如果有自定义该事件,则调用自定义事件;或将在页面的
写日志;否则不会提示!
onMaxSizeExceed 文件大小超出的响应事件
								      onMaxSizeExceed: function(file) {
								      	console.log("最大文件大小: " + file.limited
								      	 + " 但是" + file.name + " 是:" + file.size);
								      }
								      	/**
								      	 * @file    单个文件的基本信息(id, name, size, limited, formatSize, formatLimited)
								      	 */
								      	onMaxSizeExceed: function(file);
同上
onRepeatedFile 有重复文件选择的响应事件(注意:不同文件夹下的相同文件不认为是同一文件)
								      onRepeatedFile: function(file) {
								      	console.log("文件: " + file.name
								      	 + " 大小:" + file.size + "已存在于上传队列中");
								      	 return flase;
								      }
								      	/**
								      	 * @file    单个文件的基本信息(id, name, size, limited, formatSize, formatLimited)
								      	 * @return  true: 加入上传队列,false:忽略该文件
								      	 */
								      	onRepeatedFile: function(file);
同上
onFileCountExceed 文件数量超出的响应事件
								      onFileCountExceed: function(selected, limit) {
								      	console.log("最多文件数量: " + limit 
								      	+ " 但已选择" + selected + "个");
								      }
								      	/**
								      	 * @selected 已经选择的文件个数
								      	 * @limit    文件个数的最大限制
								      	 */
								      	onFileCountExceed: function(selected, limit);
同上
onExtNameMismatch 文件的扩展名不匹配的响应事件
								      	/**
								      	 * @file    不匹配的文件的基本信息(id, name, size, filters ...)
								      	 */
								      	onExtNameMismatch: function(file);
同上
onAddTask 添加文件到上传列表中的响应事件
								      	/**
								      	 * @file    添加到上传列表中的文件的基本信息(id, name, size, formatSize ...)
								      	 * @dat     如果是HTML5,可以使用dat来回显数据(如,图片,小文本等等)
								      	 *       如:
								      	 *         var reader = new FileReader(); 
										 *		   reader.readAsDataURL(dat.file); 
										 *		   reader.onload = function(evt) {
										 *		       var img = '';
										 *		   }
								      	 */
								      	onAddTask: function(file, dat);
同上
onCancel 取消上传文件的响应事件
								      onCancel : function(file) {
								      	console.log("文件: " + file.name 
								      	+ "|" + file.size + " 已取消上传");
								      }
								      	/**
								      	 * @file    取消上传的文件
								      	 */
								      	onCancel : function(file);
同上
onStop 停止上传文件的响应事件
								      onStop : function() {
								      	console.log("Stopped!");
								      }
								      	onStop : function();
同上
onCancelAll 取消所有未上传文件的响应事件
								      onCancelAll : function(numbers) {
								      	console.log(numbers + " files canceled!");
								      }
								      	/**
								      	 * @numbers    取消上传的文件的数量
								      	 */
								      	onCancel : function(numbers);
同上
onComplete 单个文件上传完毕的响应事件
								      onComplete : function(file) {
								      	console.log("文件: " + file.name 
								      	+ "|" + file.size + " 已上传成功!");
								      }
								      	/**
								      	 * @file    上传完的文件
								      	 */
								      	onComplete: function(file);
同上
onQueueComplete 所有文件上传完毕的响应事件
onQueueComplete: function(msg);
同上
onUploadError 文件上传出错的响应事件
								      onUploadError: function(status, msg) {
								      	console.log("上传文件出错,代码:" + status
								      	 + "|错误:" + msg);
								      }
								      	/**
								      	 * @status 后台返回的状态码
								      	 * @msg    后台返回的错误信息
								      	 */
								      	onUploadError: function(status, msg);
同上
onDestroy Stream销毁的响应函数
								      onDestroy: function() {
								      	console.log("Stream插件已销毁!");
								      }
								      	onDestroy: function();
同上

 

方法

方法名 说明 示例
upload() 开始上传文件(一般是在autoUploading=false才调用) new Stream(config).upload();
stop() 停止上传文件(不会删除文件) new Stream(config).stop();
cancel() 取消未上传的文件(包含正在上传但未上传完的文件) new Stream(config).cancel();
disable() 禁用文件选择按钮 var stream = new Stream(config); stream.disable();
enable() 启用文件选择按钮 var stream = new Stream(config); stream.enable();
destroy() 销毁Stream var stream = new Stream(config); stream.destroy();stream=null;
showBrowseBlock() 显示文件选择按钮 var stream = new Stream(config); stream.showBrowseBlock();
hideBrowseBlock() 隐藏文件选择按钮(Flash: 如设置display:none;会导致文件不能上传,特提供此方法) var stream = new Stream(config); stream.hideBrowseBlock();

 

常见问题:

  • Q:IE9及其以下能否支持断点续传?
  • 不能。微软的silverlight能支持,但是微软本身也放弃了这种技术(坑太多,不稳定,需要安装额外插件,兼容页面很困难,浏览器容易死掉)。建议引导用户转向高级的浏览器。
  • Q:微信扫码不能上传文件?
  • iOS版本可以,安卓部分不行,具体参考这里
  • Q:Firefox低版本不能传JSESSIONID到后台?
  • 出现这个问题,是网页中嵌入了frame或iframe,需要自定义参数
    frmUploadURL : "/fd;JSESSIONID=xxxx"
  • Q:localhost域名在IE9及其以下不能多选文件上传?
  • 原因未知,解决方法使用127.0.0.1访问!
  • Q:怎么把tokenURL也搞成支持跨域上传?
  • 1. 配置tokenURL: http://你的服务器/tokenURL;
  • 2. 修改源码TokenServlet新增方法StreamServletdoOptions方法。
  • Q:Chrome某些版本下,一次拖拽最多只能选择100个文件(或文件夹下的子文件)上传?
  • 原因未知,猜测应该是Chrome拖拽的限制,请使用文件选择对话框的形式上传文件,关闭拖拽上传!如果想选择对话框的形式也支持文件夹上传,请在类似代码<input type='file' 加上directory属性(两处)。
  • git上源代码已经修复。
  • Q:自定义UI下,Flash模式没法上传文件?
  • 大部分情况是,在某个响应函数中,把Flash插件(或父Dom)设为隐藏了,即,display:none。解决方法:取消display:none;通过width,height属性来变相解决!
  • Q:非tomcat服务器,如Resin, FLash上传时,上传至99.9%出现错误?
  • 跟踪代码发现FileItemIterator iter = upload.getItemIterator(req);中,iter取不到值。应该服务器的配置问题(如服务器文件大小限制),除了tomcat个人一般不玩企业级服务器,爱莫能助。
  • Q:系统提供的DEMO出现404错误?
  • 这是由于ContextPath问题引起的,默认ContextPath值为/,所以请确保stream-v*.war重命名为ROOT.war。如果想保留自有的ContextPath,请自定义参数:swfURLtokenURLfrmUploadURLuploadURL
  • Q:默认文件上传后,都保存在哪里?
  • 默认情况下,Java版本,文件都保存在java.io.tmp属性指向的文件夹,一般是在$TOMCAT_HOME/temp/tmp/var/folder (Mac)
  • Q:默认文件上传后,想使用FTP、云存储的方式存储文件?
  • 需要自己修改代码,在文件上传完毕,调用相关其他存储方式。如果您的程序主要是处理大文件上传,也可以修改成HTML5方式获取到多少字节,就立即上传至您的存储点(一般建议上传完毕之后再上传至存储点)。
  • Q:JQuery-ui或其他弹出框第二次打开时,会出现多次选择文件的窗口?
  • 这是因为在同一网页中多次初始化Stream插件,即多次调用类似new Stream(config)的代码!请确保只初始化一次!
  • Q:后台是否有做相关认证?
  • token参数有传递,但没有认证逻辑。另外文件大小、类型等前台有验证,但后台没有相关的处理,个人建议,下载源码后,修改成需要的逻辑。
  • Q:如何自定义上传文件的保存路径?
  • 在V1.5+的版本中,配置文件stream-config.properties 【在stream-1.5.0.9828.jar文件里面】中修改配置项:STREAM_FILE_REPOSITORY的值。
  • 在V1.5-以前的版本中只能修改JVM的启动参数set JAVA_OPTS=%JAVA_OPTS% -Djava.io.tmpdir=你的上传文件目录
  • 注意:在V1.5+的版本中,如果路径涉及到中文需要转码,在线工具:
    http://tool.oschina.net/encode?type=3
  • Q:Nginx等反向代理服务器不能实时传送数据到Tomcat后台?
  • nginx默认是缓存完所有数据(注:一次请求完成)再传送到Tomcat,官方说Nginx1.7会支持实时数据,但,目前没看到相关文档。另外,TNginx是支持将实时数据传送到后台,但,默认会缓存64K数据!
  • Q:如何把Stream插件整合到我的java项目里?
  • 1. 引入相关依赖包: commons-fileupload-1.3.jar commons-io-2.2.jar json-20090211.jar
  • 2. 引入 stream-*.jar,注意V1.5-以前的版本的版本中不提供jar包,需要您自己把cn.twinkling*下所有的文件放到WEB-INF/classes目录下(结构: classes/cn/twinkling/stream ....)
  • 3. 配置WEB-INF/web.xml,具体可以拷贝web.xml的所有servlet及servlet-mapping内容
  • 4. (不是必需的) 配置您的自定义参数(V1.5+在stream-config.properties配置, 以前的版本在web.xml配置,具体参考所下载war的示例)
  • 5. (PS) SpringMVC、Struts框架是不支持HTML5方式上传的(这类框架只能支持Form表单方式的文件上传,或者FLash),所以这类框架一般简单处理就是excludes所有Stream插件用到的URI(所有URI参考默认程序web.xml的servlet配置)。 当然FLash方式也可以由框架处理,HTML5方式由Stream插件处理(个人建议excludes方式)。

快速开始

1. 下载stream-v1.*.war包;

2. 在容器中部署stream-v1.*.war包(Tomcat示例);

      *) 进入webapps的ROOT目录,清空其他内容;

      *) 拷贝stream-v1.*.war到ROOT目录下;

      *) 解压stream-v1.*.war,linux下直接执行命令unzip stream-*.war;

3. 启动服务器,访问localhost:8080就可上传了。

 

嵌入网页

1. 实现相关接口:接口列表;注:本身自带Java语言

2. 网页中引入必要的css和js文件

									
									《link href="css/stream-v1.css" rel="stylesheet" type="text/css"》

                                
									《script type="text/javascript" src="js/stream-v1.js"》《/script》

3. 在网页中定义几个DIV元素

									
									
请选择文件

4. 配置Stream参数,并启动Stream:

								《script type="text/javascript"》
									var config = {
										multipleFiles: true, /** 多个文件一起上传, 默认: false */
										swfURL : "/swf/FlashUploader.swf", /** SWF文件的位置 */
										tokenURL : "/tk", /** 根据文件名、大小等信息获取Token的URI(用于生成断点续传、跨域的令牌) */
										frmUploadURL : "/fd;", /** Flash上传的URI */
										uploadURL : "/upload" /** HTML5上传的URI */
									};
									var _t = new Stream(config);
								《/script》

5. Yes,你应该看到她了;