一,在看文章之前,需要了解的:
1.上传文件时,可以等上传完成之后验证文件大小。如果文件是G数量级的,或许在几个小时后才收到验证结果是可能是。
(如果你想批判这一条,请看下文);
2.验证所有文件的大小。可以采用验证整个request的大小。
方法:
long totalLength = request.getContentLength();
弊端:A.表单中不仅有文件,还有其它数据,检验的文件大小就不准确;
B.不能验证单独文件的大小
3.验证单个文件:不必等用户上传几个G后才提示文件过大。假如限制单个文件为20M,等上传到20M时就提示文件过大;
(那么上传上去的20M就白白浪费了)
4.js不能获取文件大小,也不能获取file表单的文件路径;
5.利用ActiveX可以获取文件大小,但是需要降低浏览器的安全级别(每次打开浏览器都提示"安全性太低"。不现实);
6.flash不能获取文件的路径。AS3的Air才可以用File对象获取文件路径,但flash用的是FileReference对象(获取不到路径);
7.flash中不能用全路径获取本地文件(只能靠表单来选择);
8.flash可以获取文件大小、创建日期、修改日期等属性。
9.flash可以在“文件选择对话框”中过滤文件类型。
如下图:你可以只允许选择图片
二,flash组件制作
1.准备
Adobe Flash CS4.下载链接就不再贴了。
最终效果如下:
2.新建
新建一个ActionScript3.0的flash文件,场景大小设置为550x25。
注意到,图中有个FPS.
【ps】FPS:帧率,默认是1,以这个速度,你可以在“发布预览”中自己体验一下,生动得说:运行很“卡”。一般设置为30就可可以了;
3.拖放组件
找到“组件”小窗,没有的话,到“窗口”中勾选。
拖放一个“TextInput”组件、两个button组件、一个Label组件,依次放在场景上。
设置长宽分为为:
300x22;50x22;50x22;120x22;
4.组件命名
A.选中(点击)第一个按钮,在“属性”小窗。
修改组件名字为:browseBtn。
找到“组件检查器面板”按钮。
修改label的值为“浏览...”
B.同方法,修改第二个按钮的名字为clearBtn,label为“清除”。
C.同方法,修改输入框的名字为fileName,editable为"false",禁止输入。
D.同方法,修改Label组件的名字为fileSize.
三,ActionScript脚本的编写
1.准备
选中任何一个组件,在“属性”小窗,调出ActionScript面板。
出现“动作-帧”小窗,如下:
选中“场景1”-->“图层1:帧1”,右侧出现脚本编辑器。
【ps】[请认真阅读,以避免没必要的错误]
2.源码,初期demo
先贴出优化前,可以运行的代码:
【ps】看代码前,请选明确:
A.url后面请先不要加&xx=xx的参数(稍后会讲解)
B.此demo只是体验下基本语法、按钮动作、文件过滤
C.认识两个神器FileReference与ExternalInterface,前者是文件信息的封装类,后者是与js交互的类。
D.如果不成功,或弹出flash的“安全设置”,请把生成的swf放到实际项目中(本地的swf操作文件或js的话会有安全限制);
E.如果web项目用的域名访问,请在此demo的url中也用同样的域名;如果web项目是用ip访问的,这里也用ip;保持一致就可以了;最好用域名;(要不然,错了都不知道从哪里找)。
F.上传文件时参数名是“Filedata”,在页面流、逻辑流或者servlet用此变量接收。
G.请再web项目中加断点调试
var file: FileReference;
var filter:FileFilter;
var isSelect:Boolean;
var urlRequest:URLRequest=new URLRequest();
urlRequest.url = "http://xx.xxxxx.com/appname/com.xxxxxx.utils.XxxXxx.flow"; //修改url
file = new FileReference();
filter = new FileFilter("doc/docx/xls/xlsx/ppt/pptx/txt/jpg/gif/png/rar/zip", "*.doc;*.docx;*.xls;*.xlsx;*.ppt;*.pptx;*.txt;*.jpg;*.gif;*.png;*.rar;*.zip");
file.addEventListener(Event.COMPLETE, complete);
file.addEventListener(Event.OPEN,open);
file.addEventListener(Event.SELECT,select);
file.addEventListener(ProgressEvent.PROGRESS,onProgress);
browseBtn.addEventListener(MouseEvent.CLICK,selectFile);
//browseBnt.addEventListener(MouseEvent.ROLL_OVER,onOver);
//browseBnt.addEventListener(MouseEvent.ROLL_OUT,onOut);
browseBtn.buttonMode=true;
///uploadBtn.addEventListener(MouseEvent.CLICK,uploadFile);
//uploadBnt.addEventListener(MouseEvent.ROLL_OVER,onOver);
//uploadBnt.addEventListener(MouseEvent.ROLL_OUT,onOut);
///uploadBtn.buttonMode=true;
clearBtn.addEventListener(MouseEvent.CLICK,clearFile);
/*
function onOver(e:MouseEvent){
e.currentTarget.gotoAndPlay("over");
}
function onOut(e:MouseEvent){
e.currentTarget.gotoAndPlay("out");
}
*/
function selectFile(e:MouseEvent):void {
file.browse([filter]);
}
function onProgress(e:ProgressEvent){
var loaded:int;
loaded=Math.floor(e.bytesLoaded/e.bytesTotal*100);
//resultBox.appendText("[文件上传中..."+loaded+"%]\n");
}
function complete(e:Event):void {
//resultBox.appendText("[文件上传已完成!]\n");
}
function open(e:Event):void {
//resultBox.appendText("[连接:已成功连接!]\n");
}
function select(e:Event):void {
var tempTarget = e.target;
//var file2:FileReference = e.target as FileReference;
isSelect=true;
fileName.text = tempTarget.name;//e.target.name;
fileSize.text = tempTarget.size + "字节";
if(tempTarget.size > 5*1024*1024){
ExternalInterface.call("alert","文件大小过大!!!");
}
//resultBox.appendText("[文件信息]\n文件名:"+tempTarget.name+"\n文件大小:"+tempTarget.size+"\n文件类型:"+tempTarget.type+"\n文件创建日期:"+tempTarget.creationDate+"\n文件最后修改日期:"+tempTarget.modificationDate+"\n");
}
function uploadFile(e:Event){
//resultBox.appendText("[文件开始上传...]\n");
if (isSelect){
file.upload(urlRequest);
}else{
//resultBox.appendText("[错误:请先选择要上传的文件!]\n");
}
}
function clearFile(e:Event){
//清除
isSelect=false;
fileName.text = "";
fileSize.text = "";
}
【不能运行?没关系,只要能选择文件,能看到文件大小就可以了,这是初期demo,继续往下看】
3.代码解析
A.给组件注册事件,代码中的xxx.addEventListener一看便知。
B.file.browse([filter]); 弹出"文件选择"窗口,并过滤掉其他的文件类型。
C.file.upload(urlRequest); 文件用name为Filedata的变量,上传到指定的url.
D.获取文件的大小,在这个函数中:
function select(e:Event):void {
var tempTarget = e.target;
//tempTarget.size
......
}
四,JavaScript与Flash的通信
1.Flash到JavaScript
A.[AS3代码:]
ExternalInterface.call("alert","文件大小过大!!!");
调用js的alert方法。
类似于在js中写:alert("文件大小过大!!!");
B.[AS3代码:]
ExternalInterface.call("connectionStr","字符串1","字符串2");
调用js的connectionStr方法。
[JS代码:]
function connectionStr(str1,str2){
alert(str1+""+str2);
}
【ps】ExternalInterface.call的第二个参数是可变的,可以传多个参数。
C.既然提到了AS中的可变参数,那就举个例子:
function setFlashData(inPara:String, ... args):String{
var returnStr = inPara;
for(var i:uint=0; i<args.length; i++) {
returnStr += args[i];
}
return returnStr;
}
如果是往JS变量赋值的话,你懂的..
2.JavaScript到Flash
这个通信过程需要在flash中注册回调函数。还是要用到两大神器之一的ExternalInterface.
[AS3代码:]
function uploadOneFile():String {
var taStr:String;
if (isSelect){
fileSize.text = "文件开始上传";
try{
file.upload(urlRequest);
}catch(e:Error){
fileSize.text = "上传出错!";
}
}else{
fileSize.text = "请选择文件";
}
taStr = "success";
return taStr;
}
internal function initApp():void {
//标明 uploadOneFile 可以在js中用flash对象通过uploadOneFile名字直接调用
ExternalInterface.addCallback("uploadOneFile",uploadOneFile);
}
initApp();
[JS代码:]
var flash1 = $flash("flashUpload");
var reStr = flash1.uploadOneFile();
//获取flash对象
function $flash(flashId) {
if (navigator.appName.indexOf("Microsoft") != -1 )
{
return document[flashId];
} else {
return window[flashId];
}
}
【ps】稍后讲解flash对象怎么来的。
如果是js往flash赋值的话,你懂的...只要给AS中的uploadOneFile()添加参数就行了 ,
uploadOneFile(para1:String),
然后js中flash1.uploadOneFile("cmd");
五,html与Flash对象
html代码:
<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="<%=request.getContextPath()%>/xxxx/flash_upload.cab#version=9,0,0,0" width="550" height="25" id="flashUpload" align="middle">
<param name="movie" value="<%=request.getContextPath()%>/xxxx/flash_upload.swf" />
<param name="allowScriptAccess" value="always" />
<param name="swLiveConnect" value="true" />
<param name="wmode" value="opaque"/>
<embed src="<%=request.getContextPath()%>/xxxx/flash_upload.swf" width="550" allowScriptAccess="always" height="25" name="flashUpload" align="middle" type="application/x-shockwave-flash" pluginspage="" wmode="opaque" swLiveConnect="true"/>
</object>
解析:
1.swf放置的路径,自己解决
2.object标签的id为“flashUpload”,embed的name为“flashUpload”
3.添加变量<param name="wmode" value="opaque"/>
embed中添加 属性 wmode="opaque"
4.注意到3了吗?你可以体验下不加这两个会出现什么情况。
【ps】解决 flash 覆盖弹出div的问题
A.设置div的z-index是不可行的
B.适应IE<param name="wmode" value="opaque"/>
C.embed标签中添加wmode="opaque" 适应FF
5.用上文提到的函数 $flash 获取flash对象。这个函数应该还不够完善,请google下,欢迎为本帖留言。
六.为request添加参数
1.先明确说明:在url后面添加?a=aa&b=bb的方式是不行的。
[AS3代码:]
//在外部设置flash内部的值
function setFlashData(inUrl:String,inMax:int,inAll:int, ... args):String{
try{
if(null == inUrl || inUrl == ""){
return "null_url";
}
reqUrl = inUrl;
var variables:URLVariables = new URLVariables();
variables._eosFlowAction = args[0];
variables.relationId = args[1];
variables.path = args[2];
variables.filetype = args[3];
/*
for(var i:uint=0; i<args.length; i++) {
reqUrl += args[i]+"&";
}
*/
if(inMax > 0){
fileMaxSize = inMax;
}
if(inAll > 0){
fileAllSize = inAll;
}
urlRequest.url = inUrl;
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = variables;
}catch(e:Error){
return "error";
}
return "ok";
}
认真看代码,你懂的...
七,样式设置
简单的举例说明:
[AS3代码:]
字体设置:
var myTextFormat:TextFormat = new TextFormat();
myTextFormat.bold = false;
myTextFormat.color = 0x000000;
myTextFormat.size = 12;
//browseBtn.label = "浏览...";
browseBtn.setStyle("textFormat", myTextFormat);
clearBtn.setStyle("textFormat", myTextFormat);
fileName.setStyle("textFormat", myTextFormat);
fileSize.setStyle("textFormat", myTextFormat);
数字输出:
var fileSize_new :Number = 0.0;
if(tempTarget.size<1024){
fileSize_new = tempTarget.size;
fileSize.text = fileSize_new + " Byte";
}else if(tempTarget.size/1024 < 1024){
fileSize_new = tempTarget.size/1024;
fileSize_new = Number(fileSize_new.toFixed(3));
fileSize.text = fileSize_new + " K";
}else{
fileSize_new = (tempTarget.size/1024)/1024;
fileSize_new = Number(fileSize_new.toFixed(3));
fileSize.text = fileSize_new + " M";
}