user1270392
user1270392

Reputation: 3111

GWT FileUpload - Servlet options and handling response

I am new to GWT and am trying to implement a file upload functionality. Found some implementation help over the internet and used that as reference. But have some questions related to that:

  1. The actual upload or writing the contents of file on server(or disk) will be done by a servlet. Is it necessary that this servlet (say MyFileUploadServlet) extends HttpServlet? OR I can use RemoteServiceServlet or implement any other interface? If yes, which method do I need to implement/override?

  2. In my servlet, after everything is done, I need to return back the response back to the client. I think form.addSubmitCompleteHandler() can be used to achieve that. From servlet, I could return text/html (or String type object) and then use SubmitCompleteEvent.getResults() to get the result. Question is that can I use my custom object instead of String (lets say MyFileUploadResult), populate the results in it and then pass it back to client? or can I get back JSON object?

  3. Currently, after getting back the response and using SubmitCompleteEvent.getResults(), I am getting some HTML tags added to the actual response such as :

pre> Image upload successfully /pre> .

Is there a way to get rid of that?

Thanks a lot in advance!

Regards,

Ashish

Upvotes: 4

Views: 5070

Answers (1)

Felix Lechner
Felix Lechner

Reputation: 468

To upload files, I have extended HttpServlet in the past. I used it together with Commons-FileUpload.

I made a general widget for form-based uploads. That was to accommodate uploads for different file types (plain text and Base64). If you just need to upload plain text files, you could combine the following two classes into one.

public class UploadFile extends Composite {

  @UiField FormPanel uploadForm;
  @UiField FileUpload fileUpload;
  @UiField Button uploadButton;

  interface Binder extends UiBinder<Widget, UploadFile> {}

  public UploadFile() {
    initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));

    fileUpload.setName("fileUpload");

    uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
    uploadForm.setMethod(FormPanel.METHOD_POST);

    uploadForm.addSubmitHandler(new SubmitHandler() {
      @Override
      public void onSubmit(SubmitEvent event) {
        if ("".equals(fileUpload.getFilename())) {
          Window.alert("No file selected");
          event.cancel();
        }
      }
    });

    uploadButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        uploadForm.submit();
      }
    });
  }

  public HandlerRegistration addCompletedCallback(
      final AsyncCallback<String> callback) {
    return uploadForm.addSubmitCompleteHandler(new SubmitCompleteHandler() {
        @Override
        public void onSubmitComplete(SubmitCompleteEvent event) {
          callback.onSuccess(event.getResults());
        }
    });
  }
}

The UiBinder part is pretty straighforward.

<g:HTMLPanel>
  <g:HorizontalPanel>
    <g:FormPanel ui:field="uploadForm">
      <g:FileUpload ui:field="fileUpload"></g:FileUpload>
    </g:FormPanel>
    <g:Button ui:field="uploadButton">Upload File</g:Button>
  </g:HorizontalPanel>
</g:HTMLPanel>

Now you can extend this class for plain text files. Just make sure your web.xml serves the HttpServlet at /textupload.

public class UploadFileAsText extends UploadFile {

  public UploadFileAsText() {
    uploadForm.setAction(GWT.getModuleBaseURL() + "textupload");
  }
}

The servlet for plain text files goes on the server side. It returns the contents of the uploaded file to the client. Make sure to install the jar for FileUpload from Apache Commons somewhere on your classpath.

public class TextFileUploadServiceImpl extends HttpServlet {

  private static final long serialVersionUID = 1L;

  @Override
  protected void doPost(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {

    if (! ServletFileUpload.isMultipartContent(request)) {
      response.sendError(HttpServletResponse.SC_BAD_REQUEST,
          "Not a multipart request"); 
      return;
    }

    ServletFileUpload upload = new ServletFileUpload(); // from Commons

    try {
      FileItemIterator iter = upload.getItemIterator(request);

      if (iter.hasNext()) {
        FileItemStream fileItem = iter.next();

//      String name = fileItem.getFieldName(); // file name, if you need it

        ServletOutputStream out = response.getOutputStream();
        response.setBufferSize(32768);
        int bufSize = response.getBufferSize(); 
        byte[] buffer = new byte[bufSize];

        InputStream in = fileItem.openStream();
        BufferedInputStream bis = new BufferedInputStream(in, bufSize);

        long length = 0;

        int bytes; 
        while ((bytes = bis.read(buffer, 0, bufSize)) >= 0) {
          out.write(buffer, 0, bytes);
          length += bytes;
        }

        response.setContentType("text/html");
        response.setContentLength(
            (length > 0 && length <= Integer.MAX_VALUE) ? (int) length : 0);

        bis.close();
        in.close();
        out.flush();
        out.close();
      }
    } catch(Exception caught) {
      throw new RuntimeException(caught);
    }
  } 
}

I cannot recall how I got around the <pre></pre> tag problem. You may have to filter the tags on the client. The topic is also addressed here.

Upvotes: 2

Related Questions