完整 的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 >
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 >
服务器端代码:-----------------------------------------------------------------------------------------------------------
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}
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}
代码稍微有点多,请见谅。