- 沒有新回應!
今晚,原本想來寫一個 Flash 8 的上傳程式,由 Java 接收檔案並儲存起來。結果在練習這個範例的過程中,遇到些問題尚未找出答案。
Java 的程式碼如下:
package idv.ben.file;
import java.io.*;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.*;
public class Upload extends javax.servlet.http.HttpServlet
implements javax.servlet.Servlet {
static final private long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
System.out.println("==標頭==");
Enumeration enum = request.getHeaderNames();
while(enum.hasMoreElements()){
String header = (String)enum.nextElement();
System.out.println(header + " = " + request.getHeader(header));
}
// Create a new file upload handler
DiskFileUpload upload = new DiskFileUpload();
// Parse the request
List items = upload.parseRequest(request);
// Process the uploaded items
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
String fieldName = item.getFieldName();
String fileName = item.getName();
String contentType = item.getContentType();
boolean isInMemory = item.isInMemory();
long sizeInBytes = item.getSize();
System.out.println("==檔案==");
System.out.println("fieldName = " + fieldName);
System.out.println("fileName = " + fileName);
System.out.println("contentType = " + contentType);
System.out.println("isInMemory = " + isInMemory);
System.out.println("sizeInBytes = " + sizeInBytes);
String fileNameMain = fileName.lastIndexOf("")==-1?fileName:fileName.substring(fileName.lastIndexOf("")+1);
System.out.println("fileNameMain = " + fileNameMain);
File uploadDir = new File(this.getServletContext().getRealPath("/files"));
if(!uploadDir.exists())uploadDir.mkdir();
File uploadedFile = new File(this.getServletContext().getRealPath("/files/" + fileNameMain));
item.write(uploadedFile);
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}我是利用 http://jakarta.apache.org/commons/fileupload/ 提供的 FileUpload 來作操作的,當收到上傳的檔案後,會將之儲存在名叫 files 的資料夾中。
以下是 Flash 8 的程式碼:
import flash.net.FileReference;
var allTypes:Array = new Array();
var imageTypes:Object = new Object();
imageTypes.description = "Images (*.jpg, *.jpeg, *.gif, *.png)";
imageTypes.extension = "*.jpg; *.jpeg; *.gif; *.png";
allTypes.push(imageTypes);
var listener:Object = new Object();
listener.onSelect = function(file:FileReference):Void {
trace("onSelect: "+file.name);
if (!file.upload("http://localhost/Flash_Upload/Upload")) {
trace("Upload dialog failed to open.");
}
};
listener.onCancel = function(file:FileReference):Void {
trace("onCancel");
};
listener.onOpen = function(file:FileReference):Void {
trace("onOpen: "+file.name);
};
listener.onProgress = function(file:FileReference, bytesLoaded:Number, bytesTotal:Number):Void {
trace("onProgress with bytesLoaded: "+bytesLoaded+" bytesTotal: "+bytesTotal);
};
listener.onComplete = function(file:FileReference):Void {
trace("onComplete: "+file.name);
};
listener.onHTTPError = function(file:FileReference):Void {
trace("onHTTPError: "+file.name);
};
listener.onIOError = function(file:FileReference):Void {
trace("onIOError: "+file.name);
};
listener.onSecurityError = function(file:FileReference, errorString:String):Void {
trace("onSecurityError: "+file.name+" errorString: "+errorString);
};
var fileRef:FileReference = new FileReference();
fileRef.addListener(listener);
fileRef.browse(allTypes);
其實在這其中,大部分都還是從 help 的範例程式碼中擷取出來使用的,當 Flash 一開始執行時,在 frame 1 就叫用 FileReference 的 browse() 來取得使用者電腦中的檔案,若是觸發 select 事件的話,就執行 upload() 上傳。
執行之後,Flash 中 trace() 出來的訊息如下:
onSelect: IMG_2940.JPG onOpen: IMG_2940.JPG onProgress with bytesLoaded: 32768 bytesTotal: 865102 onProgress with bytesLoaded: 65536 bytesTotal: 865102 onProgress with bytesLoaded: 131072 bytesTotal: 865102 onProgress with bytesLoaded: 196608 bytesTotal: 865102 onProgress with bytesLoaded: 229376 bytesTotal: 865102 onProgress with bytesLoaded: 262144 bytesTotal: 865102 onProgress with bytesLoaded: 294912 bytesTotal: 865102 onProgress with bytesLoaded: 327680 bytesTotal: 865102 onProgress with bytesLoaded: 458752 bytesTotal: 865102 onProgress with bytesLoaded: 589824 bytesTotal: 865102 onProgress with bytesLoaded: 655360 bytesTotal: 865102 onProgress with bytesLoaded: 688128 bytesTotal: 865102 onProgress with bytesLoaded: 720896 bytesTotal: 865102 onProgress with bytesLoaded: 786432 bytesTotal: 865102 onProgress with bytesLoaded: 851968 bytesTotal: 865102 onProgress with bytesLoaded: 865102 bytesTotal: 865102 onComplete: IMG_2940.JPG
Java 這邊背後輸出的訊息卻是:
==標頭== accept = text/* content-type = multipart/form-data; boundary=----------gL6cH2ae0ei4KM7Ef1gL6Ef1gL6GI3 user-agent = Shockwave Flash host = localhost content-length = 0 connection = Keep-Alive cache-control = no-cache ==標頭== accept = text/* content-type = multipart/form-data; boundary=----------gL6cH2ae0ei4KM7Ef1gL6Ef1gL6GI3 user-agent = Shockwave Flash host = localhost content-length = 865520 connection = Keep-Alive cache-control = no-cache org.apache.commons.fileupload.FileUploadException: Processing of multipart/form-data request failed. Stream ended unexpectedly at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:429) at idv.ben.file.Upload.doPost(Upload.java:27) at javax.servlet.http.HttpServlet.service(HttpServlet.java:709) at javax.servlet.http.HttpServlet.service(HttpServlet.java:802) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:744) at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527) at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684) at java.lang.Thread.run(Thread.java:595)
為了單純測試這個上傳 Java 是否有問題,所以我另外做了一個 test.html 來讓事情單純一點,果然就可以正常上傳成功了,Java 輸出的訊息為:
==標頭== accept = */* referer = http://localhost/Flash_Upload/test.html accept-language = zh-tw content-type = multipart/form-data; boundary=---------------------------7d5731c8019a accept-encoding = gzip, deflate user-agent = Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322) host = localhost content-length = 865371 connection = Keep-Alive cache-control = no-cache ==檔案== fieldName = file fileName = C:Documents and SettingsBenMy DocumentsMy Pictures20050917_摩奇晚餐photosIMG_2940.JPG contentType = image/pjpeg isInMemory = false sizeInBytes = 865102 fileNameMain = IMG_2940.JPG
由上面的比對當中,由錯誤訊息 org.apache.commons.fileupload.FileUploadException: Processing of multipart/form-data request failed. Stream ended unexpectedly at idv.ben.file.Upload.doPost(Upload.java:27) 來看,我一開始猜測會不會是因為 Flash 對外傳遞資料時的封包結尾字元有什麼特別之處。後來看到 html 與 Flash 的兩個測試比對後,感覺上又沒有什麼關鍵的大不同之處。只是,有點詭異的是,發生錯誤時,header 標頭的部份被印出兩次,而且其中的第一次還有 content-length = 0 這個項目,第二次卻為 content-length = 865520。這些資訊讓我還有點摸不著頭緒。
我用來測試的 Flash 版本,還是先前的測試版軟體,所以我也不敢保證是否是測試版的問題,但是以前也有人可以寫出正常的效果,所以我也在想會不會是我以 Java 實做時,少考慮了什麼部份。原本以為只要 html 版的上傳能正常執行,應該前端就只是由 html 換成 Flash 而已,後端應該不用有任何改變才對,不過,現在看來,一定還有什麼遺漏之處。


