Playframework and FileUpload in RESTful

Playframework and FileUpload in RESTful

File Upload in RESTful API right now, there are only 3 options till now.
1. Base64 encode the file, at the expense of increasing the data size by around 33%.
2. Send the file first in a multipart/form-data POST, and return and ID to the client. The client then sends the metadata with the ID. The server re-associates the file and the metadata.
3. Send the metadata first, and return an ID to the client. The client then sends the file with the ID, and the server re-associates the file and the metadata.

I may choose #2 or #3. Looking at play framework Uploading Files Chapter.

1. Playframework File Upload
I will use “multipart/form-data” encoding to make the form support mix standard form data with file attachment data.

Logging Level
ch.qos.logback.classic.Level     TRACE, DEBUG, INFO, WARN and ERROR
https://www.playframework.com/documentation/2.4.3/SettingsLogger
https://www.playframework.com/documentation/2.4.3/ScalaLogging

  def upload = Action(parse.multipartFormData) { request =>
    request.body.file("file").map { file =>
      import java.io.File
      val filename = file.filename
      val contentType = file.contentType
      Ok("Resume there.")
    }.getOrElse {
      BadRequest(Json.obj("status" -> "OK", "message" -> "No files in the attachment."))
    }
  }

I was originally thinking that I may separate it into 2 steps. 1 - uploading file, 2 - parse file. But after think about this again. I may change that to 1 single step.

2. Directly Upload the File and Other Params
route configuration to upload the file content

# Resume Routes
POST    /api/v1/resume/parseFile        controllers.ResumeController.parseFile()
POST    /api/v1/resume/parseContent     controllers.ResumeController.parseContent()

The logging configuration
<configuration>

    <conversionRule conversionWord="coloredLevel" converterClass="play.api.Logger$ColoredLevel" />

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/application.log</file>
        <encoder>
            <pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
        </encoder>
    </appender>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
        </encoder>
    </appender>

    <appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE" />
    </appender>

    <appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="STDOUT" />
    </appender>

    <logger name="play" level="INFO" />
    <logger name="application" level="DEBUG" />

    <!-- Off these ones as they are annoying, and anyway we manage configuration ourself -->
    <logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
    <logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
    <logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
    <logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
    <logger name="controllers.ResumeController" level="DEBUG" />

    <root level="WARN">
        <appender-ref ref="ASYNCFILE" />
        <appender-ref ref="ASYNCSTDOUT" />
    </root>

</configuration>

Implementation Class to Deal with File

import java.io.FileInputStream

import com.wordnik.swagger.annotations._
import utils.IncludeLogger

import play.api.libs.json.{JsError, Json}
import play.api.mvc.{BodyParsers, Action, Controller}

…snip...
  implicit val resumeWrites = Json.writes[Resume]
  implicit val resumeReads = Json.reads[Resume]

  @ApiOperation(value = "parseFile",
    notes = "Parse the Resume File",
    response = classOf[Resume],
    httpMethod = "POST",
    produces = "json",
    position = 1)
  @ApiImplicitParams(Array(
    new ApiImplicitParam(
      name="body",
      value = "Resume File",
      required = true,
      dataType = "file",
      paramType = "body")))
  @ApiResponses(Array(new ApiResponse(code = 200, message = "Successful Parse Resume.", response = classOf[Resume]) ))
  def parseFile = Action(parse.multipartFormData) { request =>
    logger.debug("The request is here.")
    val resume = request.body.files.map { file =>
      val filename = file.filename
      logger.debug("file: " + filename + " " + file.contentType)
      val inputStream = new FileInputStream(file.ref.file)
      ResumeUtil.parseInputStream(inputStream)
    }
    Ok(Json.toJson(resume))
  }

Command to Play with Large Memory
>sbt clean update compile dist
>bin/classifier-play -Dconfig.file=conf/application.conf -Dhttp.port=8003 -Dhttp.address=0.0.0.0 -J-Xms1024M -J-Xmx8g -J-server

References:
http://stackoverflow.com/questions/3938569/how-do-i-upload-a-file-with-metadata-using-a-rest-web-service
http://stackoverflow.com/questions/4083702/posting-a-file-and-data-to-restful-webservice-as-json

File Upload for Scala
https://www.playframework.com/documentation/2.4.3/ScalaFileUpload
http://stackoverflow.com/questions/9452375/how-to-get-the-upload-file-with-other-inputs-in-play2

猜你喜欢

转载自sillycat.iteye.com/blog/2253380
今日推荐