1

Uploading files with GWT is usually done with a FileUpload inside a FormPanel like this:

// Create a FormPanel and point it at a service.
    final FormPanel form = new FormPanel();
    form.setAction("/myFormHandler");

    // Because we're going to add a FileUpload widget, we'll need to set the
    // form to use the POST method, and multipart MIME encoding.
    form.setEncoding(FormPanel.ENCODING_MULTIPART);
    form.setMethod(FormPanel.METHOD_POST);

    // Create a panel to hold all of the form widgets.
    VerticalPanel panel = new VerticalPanel();
    form.setWidget(panel);

    // Create a TextBox, giving it a name so that it will be submitted.
    final TextBox tb = new TextBox();
    tb.setName("textBoxFormElement");
    panel.add(tb);

    // Create a ListBox, giving it a name and some values to be associated with
    // its options.
    ListBox lb = new ListBox();
    lb.setName("listBoxFormElement");
    lb.addItem("foo", "fooValue");
    lb.addItem("bar", "barValue");
    lb.addItem("baz", "bazValue");
    panel.add(lb);

    // Create a FileUpload widget.
    FileUpload upload = new FileUpload();
    upload.setName("uploadFormElement");
    panel.add(upload);

    // Add a 'submit' button.
    panel.add(new Button("Submit", new ClickHandler() {
      public void onClick(ClickEvent event) {
        form.submit();
      }
    }));

Are there any other ways to handle file upload with GWT? Is it possible to do in with GWT-RPC or REST?

Edit: Browser requirement is Only Webkit

Cœur
  • 37,241
  • 25
  • 195
  • 267
Michael
  • 32,527
  • 49
  • 210
  • 370

1 Answers1

2

With modern browsers you can get the raw bytes of the input type=file (in a base64 data url). Having the bytes you can send them whatever the way you like.

Here's some code, displaying a file input dialog and getting the raw bytes (dataURL):

class Util {
  static native void info (Object obj) /*-{
    if ($wnd.console && $wnd.console.log) $wnd.console.log (obj)
  }-*/;

  /** Fires a "click" event on an HTML element. */
  public static native void click (final JavaScriptObject element) /*-{
    if (element.click) element.click();
  }-*/;

  /** Read a file from the local filesystem. The file should have been choosen via an `input type=file`.
   * See also: http://www.html5rocks.com/ru/tutorials/file/dndfiles/; http://www.w3.org/TR/FileAPI/ */
  public static native void readFile (JavaScriptObject inputFile, V1<String> andThen) /*-{
    var files = inputFile.files
    if ($wnd.console) $wnd.console.log ('readFile; input: ', inputFile, files)
    if (!files || !files.length) return
    var reader = new FileReader()
    reader.onload = function (progressEvent) {
      //$wnd.console.log ('read event: ', progressEvent, 'read: ', reader.result)
      andThen.@client.Closure.V1::call(Ljava/lang/Object;)(reader.result)
    }
    reader.readAsDataURL (files[0])
  }-*/;
}

// Remove old form.
final Element oldForm = Document.get().getElementById ("uploadForm");
if (oldForm != null) oldForm.getParentNode().removeChild (oldForm);

// A hidden form used to upload the files.
final FormPanel form = new FormPanel();
form.getElement().setId ("uploadForm");
final Style formStyle = form.getElement().getStyle();
formStyle.setDisplay (Display.INLINE_BLOCK); formStyle.setOverflow (Overflow.HIDDEN); formStyle.setWidth (0, Unit.PX); formStyle.setHeight (0, Unit.PX);
form.setAction ("http://.../");
form.setEncoding (FormPanel.ENCODING_MULTIPART); form.setMethod (FormPanel.METHOD_POST);
final FileUpload upload = new FileUpload(); upload.setName ("image");
form.add (upload);
RootPanel.get().add (form);

upload.addChangeHandler (new ChangeHandler() {public void onChange (final ChangeEvent event) {
  Util.info ("Loading: " + upload.getFilename());
  Util.readFile (upload.getElement(), new V1<String>() {public void call (final String dataURL) {
    Util.info ("Loaded: " + upload.getFilename() + " (url is " + dataURL.length() + " bytes)");
  }});
}});

// Trigger the upload dialogue. See also: http://aspalliance.com/articleViewer.aspx?aId=1441&pId=-1
Util.click (upload.getElement());
ArtemGr
  • 11,684
  • 3
  • 52
  • 85
  • I think that you should use convertToBlob() instead of using the base64 format since it consumes less space. What do you think? – Michael Nov 30 '13 at 14:23
  • 1
    You have the option to get an ArrayBuffer, see http://www.w3.org/TR/FileAPI/#dfn-filereader, but I used the data url because I wanted to display the image too (actually, to edit it with a canvas). And base64 is more familiar to me. What `convertToBlob` do you mean, BTW? – ArtemGr Nov 30 '13 at 14:30
  • For a canvas there is a convertToBlob() method. Not Sure if the spelling is correct but you can use it this way to get a blob from a canvas which is smaller than base64. – Michael Dec 02 '13 at 11:27
  • 1
    I see. Check http://stackoverflow.com/a/6736250/257568. Well, not every RPC mechanism will handle a Blob, while passing the data url to the server is straightforward. BTW, while looking for convertToBlob I have found a https://github.com/blueimp/JavaScript-Canvas-to-Blob library and its peer the http://blueimp.github.io/JavaScript-Load-Image/ library which you might find useful. – ArtemGr Dec 02 '13 at 14:41
  • Can you also tell me how I can bind a progress listener to get the current progress and the total? Thanks! – Michael Dec 05 '13 at 13:31
  • 1
    V1 is from this Closure library: https://raw.github.com/MSeifeddo/Closure-implementation-for-Java-5-6-and-7/master/org/mo/closure/v1/Closure.java; I guess the File API lets you bind the onprogress listener (http://www.w3.org/TR/FileAPI/#dfn-onprogress) which gets the Progress events explained here: http://www.w3.org/TR/progress-events/; not used it myself (loads from the local filesystem tend to be very fast). – ArtemGr Dec 05 '13 at 17:56
  • Oh thank you! What if I want to upload the file to my server. Do you see any way to bind an onprogress listener to the XMLHtttpReqest while sending the file to the server? When I send it over RPC/REST is there also a way of listening to the progress? – Michael Dec 06 '13 at 11:42
  • 1
    Well, I'd use JSNI or Elemental (cf. http://www.gwtproject.org/articles/elemental.html). `elemental.xml.XMLHttpRequest` has `setOnprogress`. Wrap the onprogress-related code in a try-catch to gracefully handle the old browsers. – ArtemGr Dec 06 '13 at 14:17
  • No, I don't have one available, sorry. – ArtemGr Dec 06 '13 at 14:36