GMail喜欢文件上传进度条与GWT?

时间:2009-03-09 03:08:19

标签: gwt

所有Gmail用户都应该已经注意到文件上传进度条最近已更新。

我想知道这种效果是否可以用GWT实现。 我对GWT很新,所以如果任何可以帮我测试函数的GWT源代码都会非常有帮助。

更新
我最终选择了SWFUpload。但是,此问题下的其他建议都是有效的。只需尝试不同的选项,然后选择您喜欢的选项!

9 个答案:

答案 0 :(得分:21)

看看这个图书馆:http://code.google.com/p/gwtupload/。它非常容易使用,并且在我检查过的所有浏览器和操作系统中运行良好。它使用ajax请求来计算进度。 BTW Swfupload在linux和Mac上表现不佳。

答案 1 :(得分:6)

我之前使用过这个工具:

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 - 这些行描述了回退机制的工作原理。如果您希望代码在缺少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;
    }
}

答案 2 :(得分:4)

通过swfupload-gwt

使用SWFUpload

与其他方法相比的主要优点是不需要任何特殊的服务器代码。您甚至可以上传到另一个域(如果有一个允许它的crossdomain.xml)。

答案 3 :(得分:3)

查看GWTC Upload,其中包含您正在寻找的内容。

答案 4 :(得分:3)

如果你有一个java后端编写你自己的东西是微不足道的,你只需启动一个文件上传,然后在一个计时器上轮询服务器,看看它在哪里(比如说每两秒钟)。 java文件上传二进制文件(apache commons)支持告诉你当前的进度,所以这很简单。

答案 5 :(得分:1)

最近我开始了一个名为gwtupld

的项目

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

主要目标是为最先进的浏览器提供最佳的文件上传体验 所有其他人都可以接受。目前,存在以下关键特征

  • 多个文件选择
  • 拖放
  • 进度条
  • 光滑简洁的外观
  • 所有浏览器的一致行为
  • 易于视觉定制
  • 没有外部依赖,但GWT

随意分叉并提交错误/功能提案。 您可以查看源代码,然后输入

gradlew gwtcompile devmode

并获得它将启动一个完整的功能 沙箱(具有真实文件保存的服务器端应该可以工作)

答案 6 :(得分:0)

您可以使用GwtSwfExt作为SWFUpload之上的包装器(与Swfupload-gwt lib相同),您可以从http://code.google.com/p/gwtswfext下载示例和源代码。

答案 7 :(得分:0)

创建自己的文件上传进度时,您可以让客户端显示一个不确定的条形2秒钟,然后让服务器计算估计的完成时间,然后再将其更改为确定而是每隔5,10秒推出新的估算值。这应该对交通几乎没有影响。

答案 8 :(得分:0)

有自定义multiupload插件演示http://ext4all.com/post/extjs-4-multiple-file-upload