完整 的Flex多文件上传实例
下面的例子展示了用Flex上传文件的完整代码。
- 基本实现的功能:
- 一次选取多个文件上传
- 上传过程中显示每个文件的进度
- 如果是图片,可以上传之前进行预览
- 可以选择逐个文件 上传,也可以选择同时上传多个文件,这样就是对服务器压力稍微大一些
-
- 技术点:
- 闭包方法(在c#里,也叫匿名委托方法), 根据我的体会,如果不使用闭包方法,更新进度条会是一个比较麻烦的问题,除非另外编写一个类,这个问题稍后再研究
- DataGrid中需要用到itemRenderer,从而在每行都显示进度条和删除、取消按钮
-
- 软件环境
- Flex Builder 3
- Flash player 10
- Flash player 9 (特别说明:如果使用这个版本的flashPlayer,FileFerence没有load方法和data属性,也就无法实现本地预览图片,请去掉 load和data有关调用即可)
- 在Flex Builder 3中默认是Flash Player 9,只能自己修改一下配置文件,切换到10,方法请参考Targeting Flash Player 10
-
-
还是先看一下程序吧,稍后再看代码
程序演示
源码下载:
客户端代码:fileUpload.xml-------------------------------------------------------------------------------------------------
1
<?xml version="1.0" encoding="utf-8"?>
2
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
3
layout="vertical" horizontalAlign="left" fontSize="12"
4
initialize="init()"
5
viewSourceURL="srcview/index.html">
6
<mx:NumberFormatter id="filesizeFormatter" useThousandsSeparator="true"/>
7
<mx:Script>
8
<![CDATA[
9
import mx.events.CollectionEvent;
10
import mx.formatters.NumberFormatter;
11
import mx.formatters.CurrencyFormatter;
12
import mx.collections.ArrayCollection;
13
import mx.controls.Alert;
14
private var fileRefs: FileReferenceList = new FileReferenceList();
15
//这个地址是我测试用的服务器地址
16
private var urlrequest: URLRequest = new URLRequest("http://localhost:8080/abc/UploadFile");
17
[Bindable]
18
private var selectedFiles: ArrayCollection = new ArrayCollection([]);
19
private var singleThreadFiles: Array = [];
20
[Bindable]
21
private var useSingleThread: Boolean = true;
22
private function init(): void
23
{
24
Security.allowDomain("*");
25
fileRefs.addEventListener(Event.SELECT, fileSelectHandler);
26
fileRefs.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
27
fileRefs.addEventListener(Event.COMPLETE, completeHandler);
28
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
29
}
30
private function selectFile(): void
31
{
32
fileRefs.browse([new FileFilter("Images (*.jpg, *.jpeg, *.gif, *.png)", "*.jpg;*.jpeg;*.gif;*.png"),
33
new FileFilter("所有文件(*.*)", "*.*")
34
]);
35
}
36
private function fileSelectHandler(event: Event): void
37
{
38
for each (var f: FileReference in fileRefs.fileList)
39
{
40
selectedFiles.addItem(f);
41
}
42
}
43
private function uploadFile(): void
44
{
45
for each (var f: FileReference in selectedFiles)
46
{
47
try
48
{
49
f.upload(urlrequest);
50
}
51
catch (e: Error)
52
{
53
Alert.show(e.message);
54
}
55
}
56
}
57
private function singleThreadUploadFile(): void
58
{
59
//FIFO:逐个从列表中取出,进行同步上传
60
if (singleThreadFiles.length > 0)
61
{
62
var f: FileReference = singleThreadFiles.pop() as FileReference;
63
f.addEventListener(Event.COMPLETE, doSingleUploadFileComplete);
64
f.upload(urlrequest);
65
}
66
}
67
private function doSingleUploadFileComplete(event: Event): void
68
{
69
var f: FileReference = event.target as FileReference;
70
f.removeEventListener(Event.COMPLETE, doSingleUploadFileComplete);
71
singleThreadUploadFile();
72
}
73
private function ioErrorHandler(e:IOErrorEvent): void
74
{
75
Alert.show(e.text);
76
}
77
private function completeHandler(e: Event): void
78
{
79
img.source = e.target.data;
80
}
81
private function showImage(e: Event): void
82
{
83
var f: FileReference = (e.target as DataGrid).selectedItem as FileReference;
84
f.addEventListener(Event.COMPLETE, completeHandler);
85
f.load();
86
}
87
public function removeFile(f: FileReference): void
88
{
89
var index: int = selectedFiles.getItemIndex(f);
90
if (index != -1)
91
selectedFiles.removeItemAt(index);
92
}
93
]]>
94
</mx:Script>
95
<mx:VBox>
96
<mx:HBox width="100%">
97
<mx:Button id="selectFileButton" label="浏览
" click="selectFile()"/>
98
<mx:Box width="100%" horizontalAlign="right">
99
<mx:Button click="selectedFiles.removeAll();" label="清空"/>
100
</mx:Box>
101
</mx:HBox>
102
<mx:DataGrid id="files" dataProvider="{selectedFiles}" change="showImage(event)">
103
<mx:columns>
104
<mx:DataGridColumn width="150" headerText="文件名" dataField="name" />
105
<mx:DataGridColumn headerText="大小(字节)" dataField="size">
106
<mx:itemRenderer>
107
<mx:Component>
108
<mx:Label text="{outerDocument.filesizeFormatter.format(data.size)}" textAlign="right"/>
109
</mx:Component>
110
</mx:itemRenderer>
111
</mx:DataGridColumn>
112
<mx:DataGridColumn headerText="上传进度" width="300">
113
<mx:itemRenderer>
114
<mx:Component>
115
<mx:HBox fontSize="10" fontWeight="normal" fontThickness="1">
116
<mx:Script>
117
<![CDATA[
118
import flash.profiler.showRedrawRegions;
119
import mx.controls.Alert;
120
import mx.controls.ProgressBar;
121
private function initProgressBar(event: Event): void
122
{
123
//使progressbar与file关联,从而产生进度条
124
var pb: ProgressBar = event.target as ProgressBar;
125
pb.label = "%3%%";
126
pb.setProgress(0, 100);
127
var f: FileReference = data as FileReference;
128
//使用闭包方法,更新进度条
129
f.addEventListener(ProgressEvent.PROGRESS,
130
function(event: ProgressEvent): void
131
{
132
pb.setProgress(event.bytesLoaded, event.bytesTotal);
133
}
134
);
135
f.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,
136
function (event: DataEvent): void
137
{
138
//服务器端一定要返回数据,否则,这个方法就不起作用了
139
pb.label = event.data;
140
}
141
);
142
}
143
]]>
144
</mx:Script>
145
<mx:ProgressBar verticalCenter="true" width="100%" paddingLeft="5" paddingRight="5"
146
maximum="100" minimum="0" labelPlacement="center" mode="manual"
147
label="%3%%" textAlign="left"
148
creationComplete="initProgressBar(event)"/>
149
<mx:LinkButton label="Cancel">
150
<mx:click>
151
<![CDATA[
152
var f: FileReference = data as FileReference;
153
f.cancel();
154
]]>
155
</mx:click>
156
</mx:LinkButton>
157
<mx:LinkButton label="Delete">
158
<mx:click>
159
<![CDATA[
160
var f: FileReference = data as FileReference;
161
outerDocument.removeFile(f);
162
]]>
163
</mx:click>
164
</mx:LinkButton>
165
</mx:HBox>
166
</mx:Component>
167
</mx:itemRenderer>
168
</mx:DataGridColumn>
169
</mx:columns>
170
</mx:DataGrid>
171
</mx:VBox>
172
<mx:HBox>
173
<mx:Button label="上传">
174
<mx:click>
175
<![CDATA[
176
if (useSingleThread)
177
{
178
//逐个上传
179
singleThreadFiles = selectedFiles.toArray().concat();
180
singleThreadFiles.reverse();
181
singleThreadUploadFile();
182
}
183
else
184
{
185
//多个文件同时上传
186
uploadFile();
187
}
188
]]>
189
</mx:click>
190
</mx:Button>
191
<mx:CheckBox id="checkboxSingleThread" label="同时上传多个文件" selected="{!useSingleThread}"
192
change="useSingleThread = !checkboxSingleThread.selected"/>
193
</mx:HBox>
194
<mx:Image id="img" width="400" height="300"/>
195
</mx:Application>
<?xml version="1.0" encoding="utf-8"?>2
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"3
layout="vertical" horizontalAlign="left" fontSize="12"4
initialize="init()"5
viewSourceURL="srcview/index.html">6
<mx:NumberFormatter id="filesizeFormatter" useThousandsSeparator="true"/>7
<mx:Script>8
<![CDATA[9
import mx.events.CollectionEvent;10
import mx.formatters.NumberFormatter;11
import mx.formatters.CurrencyFormatter;12
import mx.collections.ArrayCollection;13
import mx.controls.Alert;14
private var fileRefs: FileReferenceList = new FileReferenceList();15
//这个地址是我测试用的服务器地址16
private var urlrequest: URLRequest = new URLRequest("http://localhost:8080/abc/UploadFile");17
[Bindable]18
private var selectedFiles: ArrayCollection = new ArrayCollection([]);19
private var singleThreadFiles: Array = [];20
[Bindable]21
private var useSingleThread: Boolean = true;22
private function init(): void23
{24
Security.allowDomain("*");25
fileRefs.addEventListener(Event.SELECT, fileSelectHandler);26
fileRefs.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);27
fileRefs.addEventListener(Event.COMPLETE, completeHandler);28
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); 29
}30
private function selectFile(): void31
{32
fileRefs.browse([new FileFilter("Images (*.jpg, *.jpeg, *.gif, *.png)", "*.jpg;*.jpeg;*.gif;*.png"),33
new FileFilter("所有文件(*.*)", "*.*")34
]);35
}36
private function fileSelectHandler(event: Event): void37
{38
for each (var f: FileReference in fileRefs.fileList)39
{40
selectedFiles.addItem(f);41
}42
}43
private function uploadFile(): void44
{ 45
for each (var f: FileReference in selectedFiles)46
{ 47
try48
{49
f.upload(urlrequest);50
}51
catch (e: Error)52
{53
Alert.show(e.message);54
}55
} 56
}57
private function singleThreadUploadFile(): void58
{59
//FIFO:逐个从列表中取出,进行同步上传60
if (singleThreadFiles.length > 0)61
{62
var f: FileReference = singleThreadFiles.pop() as FileReference;63
f.addEventListener(Event.COMPLETE, doSingleUploadFileComplete);64
f.upload(urlrequest);65
}66
}67
private function doSingleUploadFileComplete(event: Event): void68
{69
var f: FileReference = event.target as FileReference;70
f.removeEventListener(Event.COMPLETE, doSingleUploadFileComplete);71
singleThreadUploadFile();72
}73
private function ioErrorHandler(e:IOErrorEvent): void74
{75
Alert.show(e.text);76
}77
private function completeHandler(e: Event): void78
{79
img.source = e.target.data;80
}81
private function showImage(e: Event): void82
{ 83
var f: FileReference = (e.target as DataGrid).selectedItem as FileReference;84
f.addEventListener(Event.COMPLETE, completeHandler);85
f.load();86
}87
public function removeFile(f: FileReference): void88
{89
var index: int = selectedFiles.getItemIndex(f);90
if (index != -1)91
selectedFiles.removeItemAt(index);92
}93
]]>94
</mx:Script>95
<mx:VBox>96
<mx:HBox width="100%">97
<mx:Button id="selectFileButton" label="浏览
" click="selectFile()"/>98
<mx:Box width="100%" horizontalAlign="right">99
<mx:Button click="selectedFiles.removeAll();" label="清空"/>100
</mx:Box>101
</mx:HBox>102
<mx:DataGrid id="files" dataProvider="{selectedFiles}" change="showImage(event)">103
<mx:columns>104
<mx:DataGridColumn width="150" headerText="文件名" dataField="name" />105
<mx:DataGridColumn headerText="大小(字节)" dataField="size">106
<mx:itemRenderer>107
<mx:Component>108
<mx:Label text="{outerDocument.filesizeFormatter.format(data.size)}" textAlign="right"/>109
</mx:Component>110
</mx:itemRenderer>111
</mx:DataGridColumn>112
<mx:DataGridColumn headerText="上传进度" width="300">113
<mx:itemRenderer>114
<mx:Component>115
<mx:HBox fontSize="10" fontWeight="normal" fontThickness="1">116
<mx:Script>117
<![CDATA[118
import flash.profiler.showRedrawRegions;119
import mx.controls.Alert;120
import mx.controls.ProgressBar;121
private function initProgressBar(event: Event): void122
{123
//使progressbar与file关联,从而产生进度条124
var pb: ProgressBar = event.target as ProgressBar;125
pb.label = "%3%%";126
pb.setProgress(0, 100);127
var f: FileReference = data as FileReference;128
//使用闭包方法,更新进度条129
f.addEventListener(ProgressEvent.PROGRESS,130
function(event: ProgressEvent): void131
{132
pb.setProgress(event.bytesLoaded, event.bytesTotal);133
}134
);135
f.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,136
function (event: DataEvent): void137
{138
//服务器端一定要返回数据,否则,这个方法就不起作用了139
pb.label = event.data;140
}141
); 142
}143
]]>144
</mx:Script>145
<mx:ProgressBar verticalCenter="true" width="100%" paddingLeft="5" paddingRight="5"146
maximum="100" minimum="0" labelPlacement="center" mode="manual"147
label="%3%%" textAlign="left"148
creationComplete="initProgressBar(event)"/>149
<mx:LinkButton label="Cancel">150
<mx:click>151
<![CDATA[152
var f: FileReference = data as FileReference;153
f.cancel();154
]]>155
</mx:click>156
</mx:LinkButton>157
<mx:LinkButton label="Delete">158
<mx:click>159
<![CDATA[160
var f: FileReference = data as FileReference;161
outerDocument.removeFile(f);162
]]>163
</mx:click>164
</mx:LinkButton>165
</mx:HBox>166
</mx:Component>167
</mx:itemRenderer>168
</mx:DataGridColumn>169
</mx:columns>170
</mx:DataGrid>171
</mx:VBox>172
<mx:HBox>173
<mx:Button label="上传">174
<mx:click>175
<![CDATA[176
if (useSingleThread)177
{178
//逐个上传179
singleThreadFiles = selectedFiles.toArray().concat();180
singleThreadFiles.reverse();181
singleThreadUploadFile();182
}183
else184
{185
//多个文件同时上传186
uploadFile();187
}188
]]>189
</mx:click>190
</mx:Button>191
<mx:CheckBox id="checkboxSingleThread" label="同时上传多个文件" selected="{!useSingleThread}"192
change="useSingleThread = !checkboxSingleThread.selected"/>193
</mx:HBox>194
<mx:Image id="img" width="400" height="300"/>195
</mx:Application> 服务器端代码:-----------------------------------------------------------------------------------------------------------
1
package com.java.test;
2
3
import java.io.File;
4
import java.io.IOException;
5
6
import java.util.Iterator;
7
import java.util.List;
8
9
import javax.servlet.ServletException;
10
import javax.servlet.http.HttpServlet;
11
import javax.servlet.http.HttpServletRequest;
12
import javax.servlet.http.HttpServletResponse;
13
14
import org.apache.commons.fileupload.FileItem;
15
import org.apache.commons.fileupload.FileUploadException;
16
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
17
import org.apache.commons.fileupload.servlet.ServletFileUpload;
18
public class UploadFile extends HttpServlet {
19
private static final long serialVersionUID = 5425836142860976977L;
20
21
/**
22
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
23
* @param request servlet request
24
* @param response servlet response
25
*/
26
// 定义文件的上传路径
27
private String uploadPath = "d:\\files\\";
28
// 限制文件的上传大小
29
private int maxPostSize = 100 * 1024 * 1024; //最大100M
30
public UploadFile() {
31
super();
32
}
33
public void destroy() {
34
super.destroy();
35
}
36
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
37
throws ServletException, IOException {
38
System.out.println("Access !");
39
response.setContentType("text/html;charset=UTF-8");
40
//保存文件到服务器中
41
DiskFileItemFactory factory = new DiskFileItemFactory();
42
factory.setSizeThreshold(4096);
43
ServletFileUpload upload = new ServletFileUpload(factory);
44
upload.setHeaderEncoding("utf-8");
45
upload.setSizeMax(maxPostSize);
46
try {
47
List fileItems = upload.parseRequest(request);
48
Iterator iter = fileItems.iterator();
49
while (iter.hasNext()) {
50
FileItem item = (FileItem) iter.next();
51
if (!item.isFormField()) {
52
String name = item.getName();
53
System.out.println(name);
54
try {
55
item.write(new File(uploadPath + name));
56
response.getWriter().write("上 传成功。");
57
} catch (Exception e) {
58
e.printStackTrace();
59
response.getWriter().write(e.getMessage());
60
}
61
}
62
}
63
} catch (FileUploadException e) {
64
e.printStackTrace();
65
response.getWriter().write(e.getMessage());
66
System.out.println(e.getMessage() + "结 束");
67
}
68
}
69
protected void doGet(HttpServletRequest request, HttpServletResponse response)
70
throws ServletException, IOException {
71
processRequest(request, response);
72
}
73
/**
74
* Handles the HTTP <code>POST</code> method.
75
* @param request servlet request
76
* @param response servlet response
77
*/
78
protected void doPost(HttpServletRequest request, HttpServletResponse response)
79
throws ServletException, IOException {
80
processRequest(request, response);
81
}
82
/**
83
* Returns a short description of the servlet.
84
*/
85
public String getServletInfo() {
86
return "Short description";
87
}
88
}
package com.java.test;2

3
import java.io.File;4
import java.io.IOException;5

6
import java.util.Iterator;7
import java.util.List;8

9
import javax.servlet.ServletException; 10
import javax.servlet.http.HttpServlet; 11
import javax.servlet.http.HttpServletRequest; 12
import javax.servlet.http.HttpServletResponse; 13

14
import org.apache.commons.fileupload.FileItem;15
import org.apache.commons.fileupload.FileUploadException;16
import org.apache.commons.fileupload.disk.DiskFileItemFactory;17
import org.apache.commons.fileupload.servlet.ServletFileUpload;18
public class UploadFile extends HttpServlet { 19
private static final long serialVersionUID = 5425836142860976977L;20

21
/** 22
* Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. 23
* @param request servlet request 24
* @param response servlet response 25
*/ 26
// 定义文件的上传路径 27
private String uploadPath = "d:\\files\\"; 28
// 限制文件的上传大小 29
private int maxPostSize = 100 * 1024 * 1024; //最大100M30
public UploadFile() { 31
super(); 32
} 33
public void destroy() { 34
super.destroy(); 35
} 36
protected void processRequest(HttpServletRequest request, HttpServletResponse response) 37
throws ServletException, IOException { 38
System.out.println("Access !"); 39
response.setContentType("text/html;charset=UTF-8"); 40
//保存文件到服务器中 41
DiskFileItemFactory factory = new DiskFileItemFactory(); 42
factory.setSizeThreshold(4096); 43
ServletFileUpload upload = new ServletFileUpload(factory); 44
upload.setHeaderEncoding("utf-8");45
upload.setSizeMax(maxPostSize); 46
try { 47
List fileItems = upload.parseRequest(request); 48
Iterator iter = fileItems.iterator(); 49
while (iter.hasNext()) { 50
FileItem item = (FileItem) iter.next(); 51
if (!item.isFormField()) { 52
String name = item.getName();53
System.out.println(name); 54
try { 55
item.write(new File(uploadPath + name)); 56
response.getWriter().write("上 传成功。");57
} catch (Exception e) { 58
e.printStackTrace(); 59
response.getWriter().write(e.getMessage());60
} 61
} 62
} 63
} catch (FileUploadException e) { 64
e.printStackTrace(); 65
response.getWriter().write(e.getMessage());66
System.out.println(e.getMessage() + "结 束"); 67
} 68
} 69
protected void doGet(HttpServletRequest request, HttpServletResponse response) 70
throws ServletException, IOException { 71
processRequest(request, response); 72
} 73
/** 74
* Handles the HTTP <code>POST</code> method. 75
* @param request servlet request 76
* @param response servlet response 77
*/ 78
protected void doPost(HttpServletRequest request, HttpServletResponse response) 79
throws ServletException, IOException { 80
processRequest(request, response); 81
} 82
/** 83
* Returns a short description of the servlet. 84
*/ 85
public String getServletInfo() { 86
return "Short description"; 87
} 88
} 代码稍微有点多,请见谅。
