4

I have got a multipart form with some text fields and some upload files. I need to handle this multipart post request in vertx handler so that all the uploaded files (variable number) should be read in chunks (for memory effeciency purpose). The moment I read the chunks (in foreach loop), I want to stream that out directly to the file. For multipart with text fields, I want to simply store the values to my model object.

I am quite new to vertx and therefore looking for a code snippet to achieve this but couldnt find it anywhere on the vertx documentation.

Obaid Maroof
  • 1,523
  • 2
  • 19
  • 40

3 Answers3

8

You should look at vertx-web. It contains exactly what you need:

router.route().handler(BodyHandler.create());
router.post("/some/path/uploads").handler(routingContext -> {
    MultiMap attributes = routingContext.request().formAttributes();
    // do something with the form data
    Set<FileUpload> uploads = routingContext.fileUploads();
    // Do something with uploads....
});

Hope this will help.

cdelmas
  • 840
  • 8
  • 15
1

You can process the text field and the files seperately. This could simplify your processing.

request.handler(buffer -> {
   // decode the text field here
   // ...
}).uploadHandler(upload -> {
   // read upload files in chunks here
   // ...
}).endHandler(v -> {
   // upload request end here
   // ...
});
Dharman
  • 30,962
  • 25
  • 85
  • 135
kissLife
  • 307
  • 1
  • 2
  • 9
0

I find another way to decode the multipart data in real time. With the help of netty decoder. see the snippet code below:

// the netty decoder used to decode multipart data in real time
HttpPostMultipartRequestDecoder decoder = null;

// create the decoder with reflect method
private void createDecoder(HttpServerRequest wrapper) {
    try {
        Class<?> wrapperClass = Class.forName("io.vertx.ext.web.impl.HttpServerRequestWrapper");
        Field delegateField = wrapperClass.getDeclaredField("delegate");
        delegateField.setAccessible(true);
        HttpServerRequestImpl request = (HttpServerRequestImpl) delegateField.get(wrapper);
        Field requestField = request.getClass().getDeclaredField("request");
        requestField.setAccessible(true);
        HttpRequest httpRequest = (HttpRequest) requestField.get(request);
        decoder = new HttpPostMultipartRequestDecoder(new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE),
            httpRequest);
    } catch (ClassNotFoundException | NoSuchFieldException | SecurityException | IllegalArgumentException
        | IllegalAccessException ex) {
        log.error("create decoder failed {}.", ex.getMessage());
    }
    log.info("create decoder finished. {}", decoder);
}

router.route().handler(BodyHandler.create());
router.post("/some/path/uploads").handler(routingContext -> {
    // NOTE: in vertx, request is a class of 'HttpServerRequestWrapper'
    HttpServerRequest requestWrapper = routingContext.request();
    createDecoder(requestWrapper);
    
    // decode the buffer in real time
    request.handler(buffer -> {
        decoder.offer(new DefaultHttpContent(buffer.getByteBuf()));
        if (decoder.hasNext()) {
            // get the attributes and other data 
            // ...
        }
    });
});
kissLife
  • 307
  • 1
  • 2
  • 9