start GMail喜歡文件上傳進度條與GWT?




gwt教學 (8)

所有Gmail用戶都應該已經註意到文件上傳進度條最近已更新。

我想知道這種效果是否可以用GWT實現。 我對GWT很新,所以如果任何可以幫我測試函數的GWT源代碼會非常有用。

更新
我最終選擇了SWFUpload。 但是,此問題下的其他建議都是有效的。 只需嘗試不同的選項,然後選擇您喜歡的選項!


通過swfupload-gwt使用SWFUpload

與其他方法相比的主要優點是不需要任何特殊的服務器代碼。 您甚至可以上傳到另一個域(如果有一個允許它的crossdomain.xml)。





如果你有一個java後端,編寫你自己的東西是微不足道的,你只需啟動一個文件上傳,然後在計時器上輪詢服務器,看看它在哪裡(比如說每兩秒鐘)。 java文件上傳二進製文件(apache commons)支持告訴你當前的進度,所以這很簡單。


我以前用過這個工具:

http://code.google.com/p/gwt-fileapi/

與此處的其他建議不同,它不僅提供了顯示上傳進度的正確API,還提供了通過選擇多個文件進行批量上傳的功能,還提供了拖放支持。 它還有一個HTML5之前的回退機制。

gwt-fileap我好運。 最近它在Firefox 7和8中爆發,我不得不將這個補丁應用到它 - 但是否則它的效果非常好:

@@ -57,26 +57,33 @@

     /**
      * gets the filename
-     * 
+     *
      * @return the filename
      */
     public final native String getFileName() /*-{
-        return this.fileName;
+        if(this.name)
+                    return this.name;
+         else
+                    return this.fileName;
+
     }-*/;

     /**
      * gets the file size in bytes
-     * 
+     *
      * @return the file size in bytes
      */
     public final native int getFileSize() /*-{
-        return this.fileSize;
+        if(this.size)
+                    return this.size;
+         else
+                    return this.fileSize;
     }-*/;

     /**
      * gets the MIME type of the file, may be null if the browser cannot detect
      * the type

我還必須http://code.google.com/p/gwt-fileapi/source/browse/trunk/gwt-fileapi/src/com/gwtpro/html5/fileapi/Html5FileApi.gwt.xml添加到http://code.google.com/p/gwt-fileapi/source/browse/trunk/gwt-fileapi/src/com/gwtpro/html5/fileapi/Html5FileApi.gwt.xml - 這些行描述了回退機制的工作原理。 如果您希望代碼在缺少HTML5的情況下回退到下面顯示的SWFUploader實現,您可以執行類似的操作。

    <define-property name="fileapi.support" values="yes,no" />

    <property-provider name="fileapi.support"><![CDATA[
                   var input=document.createElement('input');
                    input.setAttribute('type','file');
                    return input.files==null?'no':'yes';
    ]]></property-provider>


    <replace-with
            class="com.gwtpro.html5.fileapi.client.ui.FileInput.FileInputImplHtml5">
            <when-type-is
                    class="com.gwtpro.html5.fileapi.client.ui.FileInput.FileInputImpl" />
            <when-property-is name="fileapi.support" value="yes" />
            <any>
                    <when-property-is name="user.agent" value="ie8" />
                    <when-property-is name="user.agent" value="safari" />
                    <when-property-is name="user.agent" value="gecko1_8" />
                    <when-property-is name="user.agent" value="opera" />
                    <when-property-is name="user.agent" value="chrome" /> 
            </any>
    </replace-with>

這是我在我的應用程序中使用它的方式:

這是描述抽象的接口:

public interface FileUpload {
    public void uploadFiles();
    public Widget getWidget();
    public void initialize(Grid updateTable, Uploader uploader, String url, boolean createDropHandler);
    public void setDisabled(boolean b);
    public  void readyToPaint();
    public void reset();

}

以下是界面的gwt-fileapi實現:

package com.hierarchycm.gxt.client.fileUpload;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.gwtpro.html5.fileapi.client.FileApiSupport;
import com.gwtpro.html5.fileapi.client.drop.DropHandler;
import com.gwtpro.html5.fileapi.client.file.File;
import com.gwtpro.html5.fileapi.client.file.FileEvent;
import com.gwtpro.html5.fileapi.client.file.FileEvent.FileEventHandler;
import com.gwtpro.html5.fileapi.client.ui.FileInput;
import com.gwtpro.html5.fileapi.client.upload.UploadRequest;
import com.gwtpro.html5.fileapi.client.upload.UploadRequestBuilder;
import com.gwtpro.html5.fileapi.client.upload.UploadRequestCallback;

public class FileUploadHtmlImpl extends FileInput implements FileUpload {

    private Grid uploadTable;   
    int currentFile =0;
    String url;
    File[] files;   
    UploadRequestBuilder fileUploader;
    Uploader uploader;

    public FileUploadHtmlImpl() {

    }

    FileUploadHtmlImpl(Grid updateTable, Uploader uploader, String url) {
        this(updateTable, uploader, url, true);
    }

    FileUploadHtmlImpl(Grid updateTable, Uploader uploader, String url, boolean createDropHandler) {
        initialize(updateTable, uploader, url, createDropHandler);
        //this.setCallback(getMyCallback());
    }

    public void initialize(Grid updateTable, Uploader uploader, String url, boolean createDropHandler){
        this.url = url;
        this.uploadTable = updateTable;
        this.uploader = uploader;
        this.setAllowMultipleFiles(true);
        this.addChangeHandler(new ChangeHandler() {
                @Override
                public void onChange(ChangeEvent event) {
                    addFiles(FileUploadHtmlImpl.this.getFiles());   
                    uploadFiles();
                }
          });

        if (createDropHandler) {
            createDropHandler();
        }
    }

     private File[] jsArrToArr (JsArray<File> ipFiles) { 

         File [] result = new File [ipFiles.length()];       
         for (int i = 0; i < ipFiles.length(); ++i) {
             result[i] = ipFiles.get(i);
         }
         return result;
     }

    private UploadRequestCallback getMyCallback() {
        return new UploadRequestCallback() {

            @Override
            public void onError(UploadRequest request, Throwable exception) {
                uploadTable.setText(currentFile + 1, 2, "failed: " + exception.getMessage());
                uploadNextFile(currentFile + 1);
            }

            @Override
            public void onResponseReceived(UploadRequest request, Response response) {
                uploadTable.setText(currentFile + 1, 2, "success: " + response.getText());
                uploadNextFile(currentFile + 1);

                //If we just finished uploading  do your thing
                if (currentFile == files.length) {
                    setDisabled(false);
                    uploader.uploadDoneEventHandler();
                }
            }

            @Override
            public void onUploadProgress(UploadRequest request, int bytesUploaded) {
                uploadTable.setText(currentFile + 1, 2, bytesUploaded + "");
            }
        };
    }

    public void createDropHandler() {
          RootPanel rootPanel = RootPanel.get();
          DropHandler dropHandler = new DropHandler(rootPanel);
            this.fileUploader = new UploadRequestBuilder(url);
            this.fileUploader.setCallback(getMyCallback());
            dropHandler.addFileEventHandler(new FileEventHandler() {

                @Override
                public void onFiles(FileEvent event) {
                    addFiles(jsArrToArr(event.getFiles()));
                    uploadFiles();
                }
            });
    }

     private void addFiles (File[] ipFiles) {
            files = ipFiles;
            uploadTable.clear();
            uploadTable.resize(files.length + 1, 3);
            uploadTable.setText(0, 0, "File name");
            uploadTable.setText(0, 1, "File size");
            uploadTable.setText(0, 2, "Progress");
            for (int i = 0; i < files.length; ++i) {                
                uploadTable.setText(i + 1, 0, files[i].getFileName());                          
                uploadTable.setText(i + 1, 1, files[i].getFileSize() + "");
                uploadTable.setText(i + 1, 2, "");
            }
    }

    public void uploadNextFile(int index) {
            for (String paramName : uploader.getPostParams().keySet()) {
                fileUploader.setHeader(paramName, uploader.getPostParams().get(paramName));                                     
            }

            currentFile = index;
            this.setDisabled(true);
            if (index < this.files.length) {
                try {
                    this.fileUploader.setHeader("itemName", files[currentFile].getFileName());
                    this.fileUploader.sendFile(files[currentFile]);
                } catch (RequestException e) {
                    this.uploadTable.setText(index + 1, 2, "failed: " + e.getMessage());
                    uploadNextFile(index + 1);
                }
            }


     }

    public void uploadFiles() {
        uploadNextFile(0);
    }

    @Override
    public Widget getWidget() {
        return this;
    }

    @Override
    public void readyToPaint() {
        //no need to do anything - already painted for non swf
    }

    @Override
    public void reset() {
        // TODO Auto-generated method stub

    }

    private void showCapabilities() {
        RootPanel
                .get("status")
                .getElement()
                .setInnerHTML(
                        "Drag and Drop Support: "
                                + (FileApiSupport.isDragDropSupported() ? "Yes"
                                        : "No")
                                + "<br/>HTTPXmlRequest Level 2: "
                                + (FileApiSupport.isHttpXmlRequestLevel2() ? "Yes"
                                        : "No")
                                + "<br/>File input supports multiple files: "
                                + (FileApiSupport
                                        .isMultipleFileInputSupported() ? "Yes"
                                        : "No")+"<br/><br/>");
    }

}

這是相同界面的SWFUpload http://code.google.com/p/swfupload-gwt/實現:

package com.hierarchycm.gxt.client.fileUpload;

import com.extjs.gxt.ui.client.widget.Html;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Widget;

public class FileUploadSwfImpl extends Html implements FileUpload {

    SwfUploadUtil swfUploadUtil = null;
    private Uploader uploader;
    private String url;
    private boolean createDropHandler;
    private Grid updateTable;



    static int uploadId = 0; 
    static String divTagId;

    public FileUploadSwfImpl() {
        divTagId = "swfupload" + uploadId++;
        String divTag = "<div id=\"" + divTagId + "\"></div";
        this.setHtml(divTag);
    }

    @Override
    public void uploadFiles() {
        swfUploadUtil.startUpload();        
    }

    @Override
    public Widget getWidget() {     
        return this;
    }

     public  void readyToPaint() {      

         swfUploadUtil =  new SwfUploadUtil(uploader, updateTable, divTagId, url);       
     }

    @Override
    public void initialize(Grid updateTable, Uploader uploader, String url, boolean createDropHandler) {

        this.uploader = uploader;
        this.url = url;
        this.createDropHandler = createDropHandler;
        this.updateTable = updateTable;

    }

    @Override
    public void setDisabled(boolean b) {

        swfUploadUtil.setDisabled(b);
        this.disabled = true;

    }

    @Override
    public void reset() {
        swfUploadUtil.reset();

    }
}

這是FileUploadSwfImpl依賴的實用程序:

package com.hierarchycm.gxt.client.fileUpload;

import java.util.HashMap;

import org.swfupload.client.File;
import org.swfupload.client.SWFUpload;
import org.swfupload.client.UploadBuilder;
import org.swfupload.client.SWFUpload.ButtonAction;
import org.swfupload.client.SWFUpload.ButtonCursor;
import org.swfupload.client.event.DialogStartHandler;
import org.swfupload.client.event.FileDialogCompleteHandler;
import org.swfupload.client.event.FileQueuedHandler;
import org.swfupload.client.event.UploadCompleteHandler;
import org.swfupload.client.event.UploadErrorHandler;
import org.swfupload.client.event.UploadProgressHandler;
import org.swfupload.client.event.UploadSuccessHandler;
import org.swfupload.client.event.FileDialogCompleteHandler.FileDialogCompleteEvent;
import org.swfupload.client.event.FileQueuedHandler.FileQueuedEvent;
import org.swfupload.client.event.UploadCompleteHandler.UploadCompleteEvent;
import org.swfupload.client.event.UploadErrorHandler.UploadErrorEvent;
import org.swfupload.client.event.UploadProgressHandler.UploadProgressEvent;
import org.swfupload.client.event.UploadSuccessHandler.UploadSuccessEvent;

import com.extjs.gxt.ui.client.widget.form.TextArea;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Grid;

public class SwfUploadUtil {

    HashMap<String, Integer> filenameRowHm = new HashMap<String, Integer>(); 

    private boolean resetIssued;

    SWFUpload swfUpload = null;
    private HashMap <String, File> files = new HashMap<String, File>();     
    int tableRow = 5;   
    Uploader uploader = null;
    private Grid updateTable;
    private String divName;
    private String url;

    synchronized private void removeFile(String id) {
        files.remove(id);
    }       

    public SwfUploadUtil(Uploader uploader, Grid updateTable,  String divName, String url){
        reset();
        this.uploader = uploader;
        this.updateTable = updateTable;
        this.divName = divName;
        this.url = url;

        this.swfUpload = loadSWFUpload();
        updateTable.resize(5, 5);
        updateTable.setText(2, 0, "Upload URL:" );
        updateTable.setText(2, 1, url );        
        updateTable.setText(4, 0, "File Name" );
        updateTable.setText(4, 1, "Bytes In");
        updateTable.setText(4, 2, "Status");
        updateTable.setText(4, 3, "File Size" );
        updateTable.setText(4, 4, "Server response" );

    }


    public SWFUpload loadSWFUpload() {

        this.updateTable = updateTable;

        if (swfUpload == null) {        
            final UploadBuilder builder1 = new UploadBuilder();
            builder1.setHTTPSuccessCodes(200, 201);
            builder1.setFileTypes("*.webm;*.asf;*.wma;*.wmv;*.avi;*.flv;*.swf;*.mpg;*.mpeg;*.mp4;*.mov;*.m4v;*.aac;*.mp3;*.wav;*.png;*.jpg;*.jpeg;*.gif");
            builder1.setFileTypesDescription("Images, Video & Sound");

            builder1.setButtonPlaceholderID(divName);
            builder1.setButtonImageURL("./images/XPButtonUploadText_61x22.png");
            builder1.setButtonCursor(ButtonCursor.HAND);
            builder1.setButtonWidth(61);
            builder1.setButtonHeight(22);
            builder1.setButtonAction(ButtonAction.SELECT_FILES);

            builder1.setUploadProgressHandler(new UploadProgressHandler() {

                public void onUploadProgress(UploadProgressEvent e) {

                    File f = e.getFile();                   
                    updateTable.setText(getFilenameRow(f), 2, String.valueOf(e.getBytesComplete()));

                }
            });

            builder1.setUploadSuccessHandler(new UploadSuccessHandler() {
                public void onUploadSuccess(UploadSuccessEvent e) {
                    File f = e.getFile();
                    updateTable.setText(getFilenameRow(f), 4, e.getServerData());
                }
            }); 

            builder1.setUploadErrorHandler(new UploadErrorHandler() {
                public void onUploadError(UploadErrorEvent e) {
                    File ff = e.getFile(); 
                    String message = e.getMessage(); 
                    if (message == null || message.trim().length() == 0) {
                        message = "upload failed"; 
                    }               
                    updateTable.setText(getFilenameRow(ff), 2, String.valueOf(message));

                    removeFile(ff.getId()); 
                    if (files.values().size() > 0) {
                        ff = files.values().iterator().next(); 
                        updateTable.setText(getFilenameRow(ff), 2, "Started");
                        swfUpload.startUpload(ff.getId());                      
                    }
                }
            }); 

            builder1.setUploadURL(url); 

            builder1.setDialogStartHandler(new DialogStartHandler() {
                @Override
                public void onDialogStart() {
                    if(resetIssued == true) { 
                        filenameRowHm.clear();
                        resetIssued = false;
                    }               
                }                   
            }
            );

            builder1.setUploadCompleteHandler(new UploadCompleteHandler() {
                public void onUploadComplete(UploadCompleteEvent e) {
                    File f = e.getFile(); 

                    updateTable.setText(getFilenameRow(f), 2, "Done");

                    removeFile(f.getId()); 
                    if (files.values().size() > 0) {
                        File ff = files.values().iterator().next(); 

                        updateTable.setText(getFilenameRow(ff), 2, "Started");
                        swfUpload.startUpload(ff.getId()); 
                    } else {                    
                        uploader.uploadDoneEventHandler();
                    }
                }
            });

            builder1.setFileQueuedHandler(new FileQueuedHandler() {
                public void onFileQueued(FileQueuedEvent event) {

                    File f = event.getFile();                   
                    updateTable.setText(getFilenameRow(f), 2, "Queued");                    
                    files.put(f.getId(), f); 
                }
            });

            builder1.setFileDialogCompleteHandler(new FileDialogCompleteHandler() {
                public void onFileDialogComplete(FileDialogCompleteEvent e) {                                                   



                    updateTable.setText(2, 0, "Number of files");
                    updateTable.setText(2, 1, String.valueOf(files.values().size()));

                    for(File f : files.values()) {
                        getFilenameRow(f);
                    }

                    if (files.values().size() > 0) {

                        for (String paramName : uploader.getPostParams().keySet()) {
                            swfUpload.addPostParam(paramName,uploader.getPostParams().get(paramName));                          
                        }   
                    }
                }
            });
            swfUpload = builder1.build();

        }

        return swfUpload;

    }

    public int getFilenameRow (File f) {
        Integer filenamerow = filenameRowHm.get(f.getId());

        if (filenamerow == null) {
            updateTable.resize(tableRow+1, 5);
            filenamerow = new Integer(tableRow++);
            updateTable.setText(filenamerow.intValue(), 0, f.getName());
            updateTable.setText(filenamerow.intValue(), 3, String.valueOf(f.getSize()));
            //updateTable.setText(filenamerow.intValue(), 3, String.valueOf(f));
            filenameRowHm.put(f.getId(), filenamerow);
        }

        return filenamerow.intValue();
    }

    public void startUpload() {
        uploader.uploadStartedEventHandler();
        swfUpload.startUpload();
    }

    public void setDisabled(boolean disabled) {
        swfUpload.setButtonDisabled(disabled);


    }

    public void reset() {
        // TODO Auto-generated method stub
        resetIssued = true;
    }
}

查看GWTC上傳 ,它具有您正在尋找的確切實現。


最近我開始了一個名為gwtupld的項目

http://github.com/kompot/gwtupld/

主要目標是為最先進的瀏覽器提供最佳的文件上載體驗,並為所有其他瀏覽器提供可接受的可用性。 到目前為止,存在以下關鍵特徵

  • 多個文件選擇
  • 拖放
  • 進度條
  • 光滑簡潔的外觀
  • 所有瀏覽器的一致行為
  • 易於視覺定制
  • 沒有外部依賴,但GWT

隨意分叉並提交錯誤/功能提議。 您可以查看源代碼,然後鍵入

gradlew gwtcompile devmode

並獲得它將啟動一個功能齊全的沙箱(服務器端真正的文件保存應該工作)