How to get the upload file with other inputs in play2?
Asked Answered
B

4

25

In html, a form with multipart data:

<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>

How to write the action Files upload?

I know how to get a uploaded file:

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

And how to get submitted inputs:

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

But how to combine them together?

I don't find a suitable type for file can be used in Form(tuple(...)), and neither a way to get input value in request.body.

Burkes answered 26/2, 2012 at 10:31 Comment(0)
I
27

This answer is for Java, but you should be able to adapt it to Scala fairly easily.

What you need to do is define a Model for all the fields in your form except the file. Then use the file-upload API as normal to retrieve the file.

For example, this is what I did:

The Form (in 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>
}

The Model (models/UploadResource.java):

public class UploadResource {
    @Required
    public String lang;

    @Required
    public String country;

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

The Controller (controllers/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 */
     }
}

I hope this helps.

Implication answered 6/3, 2012 at 15:48 Comment(2)
What if you want to store the location of file in the model? Otherwise, how will you know where the file is located after you process it? I guess I'm missing what the "file-upload API" is - commons.apache.org/proper/commons-fileupload/using.html ?Builtup
@SkylarSaveland - this code just lets you get the form data and the file. Once you have the file (the resourceFile in my example), you can move it to wherever you want to store it, and update your model with the location and filename.Implication
C
13

An example in Scala where the form field is required:

Model:

case class Specs (userid: String)

Controller:

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.")
      }
   }
}
Catwalk answered 25/4, 2012 at 19:6 Comment(0)
C
3

Another example how to do this can be this:

Model:

case class Specs(userId: String)

Controller

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)
      }
   }


 )

Dont forget to name the file, because you might end up wondering what went wrong.

Centipoise answered 20/4, 2015 at 17:54 Comment(0)
F
2

I was uploading a file using angular, with other form parameters. I created mine as below and it works.

Angular Function

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 Controller

/**
*
*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");
    }
}
Falstaffian answered 27/2, 2016 at 13:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.