How to get the upload file with other inputs in pl

2019-01-30 15:40发布

问题:

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.

回答1:

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.



回答2:

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


回答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.



回答4:

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