Flow.js and Java Servlet upload file 0 bytes

1.1k views Asked by At

I added flow.js in my proyect following the instructions and the call to my java servlet:

localhost:8080/WebExample/UploadImgServlet?flowChunkNumber=1&flowChunkSize=1048576&flowCurrentChunkSize=693916&flowTotalSize=693916&flowIdentifier=693916-image2png&flowFilename=image2.png&flowRelativePath=image2.png&flowTotalChunks=1`

In my servlet I get all parameters of the url (flowChuckNumber, flowChuckSize, etc) but when I try to get the file (request.getInputStream()), it's empty and upload 0 bytes.

Where is the problem? Any Idea?

I found a similar question but it was with PHP...

My code:

HTML(the image is displayed):

...
...
<div flow-init="{singleFile:true}"
 flow-file-added="!!{png:1,gif:1,jpg:1,jpeg:1}[$file.getExtension()]"
     flow-files-submitted="$flow.upload()"
     flow-file-success="$file.msg = $message">
         <div class="drop" flow-drop ng-class="dropClass">

        <md-button class="md-raised md-primary" type="file" flow-btn>Upload Image</md-button>
    <b>OR</b>
    Drag And Drop your image here
  </div>
    <div class="thumbnail" ng-show="!$flow.files.length">
      <img src="http://www.placehold.it/200x150/EFEFEF/AAAAAA&text=no+image" alt="Image"/>
    </div>
    <div class="thumbnail" ng-show="$flow.files.length">
      <img flow-img="$flow.files[0]" />
    </div>

  <table>
    <tr ng-repeat="file in $flow.files">
        <td>{{$index+1}}</td>
        <td>{{file.name}}</td>
        <td>{{file.msg}}</td>
    </tr>
  </table>
</div>
...
...

App AngularJs:

var app = angular.module("webexample", ['ngMaterial', 'ngNotify','uiGmapgoogle-maps','flow'])
.config(['flowFactoryProvider', function (flowFactoryProvider) {
      flowFactoryProvider.defaults = {
        target: '/WebExample/UploadImgServlet',
        permanentErrors: [404, 500, 501],
        maxChunkRetries: 1,
        chunkRetryInterval: 5000,
        simultaneousUploads: 1
      };
      flowFactoryProvider.on('catchAll', function (event) {
        console.log('catchAll', arguments);
      });
      // Can be used with different implementations of Flow.js
      // flowFactoryProvider.factory = fustyFlowFactory;
    }])
    .directive('appDownloadUrl', [function () {
      return {
        restrict: 'A',
        link: function(scope, element, attrs) {
          element.bind('dragstart', function (event) {
            var config = scope.$eval(attrs.appDownloadUrl);
            if (!config.disabled) {
              var data = config.mime + ':' + config.name + ':' + window.location.href + config.url;
                        console.log("data: "+data);
              event.dataTransfer.setData('DownloadURL', data);
            }
          });
        }
      };
    }])
    .directive("appDragstart", [function () {
      return function(scope, element, attrs) {
        element.bind('dragstart', function (event) {
          scope.$eval(attrs.appDragstart);
        });
      }
    }]).directive("appDragend", [function () {
      return function(scope, element, attrs) {
        element.bind('dragend', function (event) {
          scope.$eval(attrs.appDragend);
        });
      }
    }]).run(function ($rootScope) {
      $rootScope.dropEnabled = true;
    });

My Servlet (I followed this example):

protected void doService(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException
    {
        LOGGER.debug("[UploadImgServlet - doService] - init");

        int resumableChunkNumber  = getResumableChunkNumber(request);

        ResumableInfo info = getResumableInfo(request);
        //info contains all flow parameters of the url.

        RandomAccessFile raf = new RandomAccessFile(info.resumableFilePath, "rw");

        //Seek to position
        raf.seek((resumableChunkNumber - 1) * info.resumableChunkSize);

        //Save to file
        InputStream is = request.getInputStream();
        long readed = 0;

        long content_length = request.getContentLength();
        //**PROBLEM: request.getContentLength return -1 so read 0 bytes**


        byte[] bytes = new byte[1024 * 100];
        while(readed < content_length) {
            int r = is.read(bytes);
            if (r < 0)  {
                break;
            }
            raf.write(bytes, 0, r);
            readed += r;
        }
        raf.close();
...
...
3

There are 3 answers

0
otterslide On BEST ANSWER

The input stream will be empty because flowjs posts the content using MultiPart by default. The author of the Java code specified that "Octet" should be used for uploads, not multi-part.

UploadServlet accepts Resumable.js Upload with 'octet'

You need to add "method:octet" to your init,

<div flow-init="{singleFile:true, method:octet}"

I am using Spring, so I just used MultipartHttpServletRequest to get the posted data with MultiPart instead because MultiPart is more common.

This is how I received the contents of the file:

Iterator<String> itr = request.getFileNames();

/* Iterate each file, there should only be one/one chunk */
while (itr.hasNext()) {
    fileUploaded = request.getFile(itr.next());
    raf.write(fileUploaded.getBytes());
}

raf.close();

I had to do more fixes to the java code provided because it was estimating the number of chunks to receive wrong, so I just used the "flowTotalChunks" parameter.

4
user207421 On

You don't need to worry about content length. The HttpServletRequest will terminate the input stream at the correct point. Just read until end of stream.

3
Jose Antonio On

I wanted a lib to upload images with more options and visually appealing (drop file from a folder, thumbnail, etc) than the default html input and I have not been able to do with Flowjs and Java Servlet, so I looked for another lib:

https://github.com/danialfarid/ng-file-upload

https://angular-file-upload.appspot.com/

With this lib, I found it easy to use with Java Servlet.

I don't mark this post as solved for if someone finds a way to do it with Flowjs.