Подтвердить что ты не робот

Загрузка файла в виде потока в play framework 2.0

Я пишу приложение java 2.0 для игры, которое позволяет пользователям загружать файлы. Эти файлы хранятся в сторонней службе, к которой я обращаюсь, используя библиотеку Java, метод, который я использую в этом API, имеет следующую подпись:

void store(InputStream stream, String path, String contentType)

Мне удалось настроить загрузку с помощью следующего простого контроллера:

public static Result uploadFile(String path) {
    MultipartFormData body = request().body().asMultipartFormData();
    FilePart filePart = body.getFile("files[]");
    InputStream is    = new FileInputStream(filePart.getFile())
    myApi.store(is,path,filePart.getContentType()); 
    return ok();
  }

Я обеспокоен тем, что это решение неэффективно, потому что по умолчанию платформа воспроизведения хранит все данные, загруженные клиентом во временном файле на сервере, а затем вызывает мой метод uploadFile() в контроллере.

В традиционном приложении сервлета я написал бы сервлет, ведущий таким образом:

myApi.store(request.getInputStream(), ...)

Я искал везде и не нашел решения. Самый близкий пример, который я нашел, - Почему возникает ошибка звонка или выполняется в Iteratee BodyParser, этот запрос зависает в Play Framework 2.0?, но я не нашел, как его изменить мои потребности.

Есть ли способ в play2 для достижения такого поведения, то есть когда данные, загруженные клиентом, "проходят" через веб-приложение напрямую в другую систему?

Спасибо.

4b9b3361

Ответ 1

Мне удалось передать данные в сторонний API, используя следующий код контроллера Scala:

def uploadFile() = 
    Action( parse.multipartFormData(myPartHandler) ) 
    {
      request => Ok("Done")
    }

def myPartHandler: BodyParsers.parse.Multipart.PartHandler[MultipartFormData.FilePart[Result]] = {
        parse.Multipart.handleFilePart {
          case parse.Multipart.FileInfo(partName, filename, contentType) =>
            //Still dirty: the path of the file is in the partName...
            String path = partName;

            //Set up the PipedOutputStream here, give the input stream to a worker thread
            val pos:PipedOutputStream = new PipedOutputStream();
            val pis:PipedInputStream  = new PipedInputStream(pos);
            val worker:UploadFileWorker = new UploadFileWorker(path,pis);
            worker.contentType = contentType.get;
            worker.start();

            //Read content to the POS
            Iteratee.fold[Array[Byte], PipedOutputStream](pos) { (os, data) =>
              os.write(data)
              os
            }.mapDone { os =>
              os.close()
              Ok("upload done")
            }
        }
   }

UploadFileWorker - действительно простой Java-класс, который содержит вызов API-интерфейсов thrid-party.

public class UploadFileWorker extends Thread {
String path;
PipedInputStream pis;

public String contentType = "";

public UploadFileWorker(String path, PipedInputStream pis) {
    super();
    this.path = path;
    this.pis = pis;
}

public void run() {
    try {
        myApi.store(pis, path, contentType);
        pis.close();
    } catch (Exception ex) {
        ex.printStackTrace();
        try {pis.close();} catch (Exception ex2) {}
    }
}

}

Это не совсем идеально, потому что я предпочел бы восстановить путь в качестве параметра для Action, но я не смог этого сделать. Таким образом, я добавил фрагмент javascript, который обновляет имя поля ввода (и, следовательно, имя_почты), и это делает трюк.