Create a gist now

Instantly share code, notes, and snippets.

Using custom multipart body parser that uses specified dir to save files
package controllers;
import java.io.File;
import java.util.List;
import play.mvc.BodyParser;
import play.mvc.BodyParser.Of;
import play.mvc.Controller;
import play.mvc.Http.MultipartFormData;
import play.mvc.Http.MultipartFormData.FilePart;
import play.mvc.Http.RequestBody;
import play.mvc.Result;
import utils.CustomParsers;
import views.html.index;
public class Application extends Controller {
public static class PermanentMultipartFormData implements BodyParser {
//location to save the files
private final File dir = new File("data");
@Override
public play.api.mvc.BodyParser<RequestBody> parser(int maxLength) {
return CustomParsers.permanentMultipartFormData(dir, maxLength);
}
}
@Of(PermanentMultipartFormData.class)
public static Result upload() {
MultipartFormData md = request().body().asMultipartFormData();
//do your thing
}
public static Result index() {
return ok(index.render("Your new application is ready."));
}
}
package utils
import java.io.File
import play.api.mvc._
import play.mvc.Http.RequestBody
import play.api.mvc.BodyParsers._
import parse._
import play.core.j.JavaParsers.DefaultRequestBody
import play.api.libs.iteratee.Iteratee
import play.api.mvc.MultipartFormData._
import play.api.libs.Files.TemporaryFile
import java.io.FileOutputStream
import scala.collection.JavaConverters._
object CustomParsers {
case class MultipartRequestBody(multipart: MultipartFormData[File]) extends RequestBody {
override lazy val asMultipartFormData = {
new play.mvc.Http.MultipartFormData {
lazy val asFormUrlEncoded = {
multipart.asFormUrlEncoded.mapValues(_.toArray).asJava
}
lazy val getFiles = {
multipart.files.map { file =>
new play.mvc.Http.MultipartFormData.FilePart(
file.key, file.filename, file.contentType.orNull, file.ref)
}.asJava
}
}
}
}
private def orDefault(maxLength: Int) = if (maxLength < 0) parse.DEFAULT_MAX_TEXT_LENGTH else maxLength
type PartHandler[A] = PartialFunction[Map[String, String], Iteratee[Array[Byte], A]]
def permanentMultipartFormData(dir: File, maxLength: Int): BodyParser[RequestBody] = {
parse.maxLength(orDefault(maxLength), parse.multipartFormData(handleFilePartAsPermanentFile(dir))).map {
_.fold(
_ => DefaultRequestBody(isMaxSizeExceeded = true),
multipart =>
MultipartRequestBody(multipart))
}
}
def handleFilePartAsPermanentFile(dir: File): PartHandler[FilePart[File]] = {
Multipart.handleFilePart {
case Multipart.FileInfo(partName, filename, contentType) =>
val file = new File(dir, filename)
Iteratee.fold[Array[Byte], FileOutputStream](new java.io.FileOutputStream(file)) { (os, data) =>
os.write(data)
os
}.map { os =>
os.close()
file
}
}
}
}
@satishkvemula

Hi,

Thank you very much for sharing this code, as I have a very similar need.

At the same time, our http end point is currently overloaded to handle different content-types, either multipart of urlencoded content-types.

Is there any way, I can get hold of the Content-Type, in the PermanentMultipartFormData.parser method, so that I can return different parsers depending on content type.

I see that BodyParsers.parse.anyContent is being passed a request object, but I am not sure how to access that in the mentioned method. The Threadlocal Http Context itself seems uninitialized at this point of time.

Please let me know. I can live with single parser option too, where during parsing it can figure out what content -type it is going to be.

regards
Satish Vemula

@msegeya

adding the import below to the scala code

import scala.concurrent.ExecutionContext.Implicits.global

Fixed some errors that i faced while using this code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment