Как загрузить файл с другими входами в play2?

В html, форма с многочастными данными:

<form action="@routes.Files.upload" method="post" enctype="multipart/form-data">
    <input type="hidden" name="groupId" value="1" />
    <input type="hidden" name="tagId" value="2" />
    <input type="file" name="file"/>
    <input type="submit" value="upload it"/>
</form>

Как написать действие Files upload?

Я знаю, как получить загруженный файл:

request.body.file("file") map {
    filepart => filepart.ref.moveTo(newFile);
}

И как получить отправленные входы:

Form(tuple("groupId" -> text, "tagId" -> text)).bindFromRequest.fold(
    errors => ...,
    params => ....
)

Но как их объединить?

Я не нашел подходящий тип для file, который можно использовать в Form(tuple(...)), и ни один способ получить входное значение в request.body.

Ответы

Ответ 1

Этот ответ для Java, но вы должны легко адаптировать его к Scala.

Что вам нужно сделать, так это определить модель для всех полей в вашей форме, кроме файла. Затем используйте API загрузки файлов как обычно для получения файла.

Например, это то, что я сделал:

Форма (в файле upload.scala.html):

@form(action = routes.UploadResourceController.doUpload(), 'enctype -> "multipart/form-data") {

    @inputText(uploadForm("lang"))
    @inputText(uploadForm("country"))
    @inputFile(uploadForm("resourceFile"))

    <p>
        <input type="submit">
    </p>
}

Модель (модели/UploadResource.java):

public class UploadResource {
    @Required
    public String lang;

    @Required
    public String country;

    /* notice a field for the file is missing */
}

Контроллер (контроллеры/UploadResourceController.java):

public static Result doUpload() {
    Form<UploadResource> filledForm = uploadForm.bindFromRequest();

    if (filledForm.hasErrors()) {
        return badRequest(views.html.upload.render(filledForm));
    } else {
        UploadResource resource = filledForm.get();
        MultipartFormData body = request().body().asMultipartFormData();
        FilePart resourceFile = body.getFile("resourceFile");

        /* Check resourceFile for null, then extract the File object and process it */
     }
}

Надеюсь, это поможет.

Ответ 2

Пример в Scala, где требуется поле формы:

Модель:

case class Specs (userid: String)

Контроллер:

object Upload extends Controller {
   val uploadForm = Form(
         mapping(
               "userid" -> nonEmptyText
         )(Specs.apply)(Specs.unapply)
   )
   def upload = Action(parse.multipartFormData) { implicit request =>
      val sp : Option[Specs] = uploadForm.bindFromRequest().fold (
            errFrm => None,
            spec => Some(spec)
      )
      request.body.file("file").map { f =>
         sp.map { spec =>
            val filePath = ... // incorporate userid
            // XXX: file read to memory b4 writing to disk. bad for large files
            f.ref.moveTo(new File(filePath), replace=true)
            Ok("File uploaded")
         }.getOrElse{
            BadRequest("Form binding error.")
         }
      }.getOrElse {
         BadRequest("File not attached.")
      }
   }
}

Ответ 3

Другой пример, как это сделать, может быть следующим:

Модель:

case class Specs(userId: String)

контроллер

def upload = Action(parse.multipartFormData) { implicit request => 
   uploadForm.bindFromRequest().fold(
   hasErrors => Ok(ourFormHTML(hasErrors),
   specs => {
      request.body.file("inputFileFieldName") match {
        case Some(file) => {
          import java.io.File
          val filename = file.filename
          val contetType = file.contentType
          file.ref.moveTo(new File(Play.application().path().getAbsolutePath + file.filename))
          Ok("congratz you did it")
        }
        case _ => Ok(ourHTML if we dont send file but want the form anyway)
      }
   }


 )

Не забывайте называть файл, потому что вы можете удивиться, что пошло не так.

Ответ 4

Я загрузил файл, используя angular, с другими параметрами формы. Я создал мой, как показано ниже, и он работает.

Angular Функция

Upload.upload({
    url: '/api/upload',
    method:'POST',
    data: {
        "file": user.profilePic, //file object
        "username": user.username

    }
}).then(function (resp) {
    //console.log('Success ' + resp.config.data.file.name + 'uploaded. Response: ' + resp.data);

}, function (resp) {
    console.log('Error status: ' + resp.status);
}, function (evt) {
    var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
    //console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
});

Контроллер Play 2.1

/**
*
*Upload user profile 
**/
public static Result upload() {
    Logger.info("Uploading images##");
    Http.MultipartFormData body = request().body().asMultipartFormData();
    Http.MultipartFormData.FilePart profile = body.getFile("file");
    if (profile != null) {
        File file = profile.getFile();

        //upload file to a directory
        //todo

        //get the username from form
          Map<String,String[]> dataPart = request().body().asMultipartFormData().asFormUrlEncoded();
          String username = dataPart.get("username")[0];

          //save/update the details with ebean

        return ok("File uploaded");
    } else {

        return status(400, "Missing file");
    }
}