2

我正在使用 Play Framework 和 ReactiveMongo DB 将上传的文件存储在 GridFS 中。这是代码:

  def saveAttachment(id: String) = Action.async(gridFSBodyParser(gridFS)) { request =>
  // here is the future file!
    val futureFile = request.body.files.head.ref
    // when the upload is complete, we add the article id to the file entry (in order to find the attachments of the article)
    val futureUpdate = for {
      file <- futureFile
      // here, the file is completely uploaded, so it is time to update the user
      updateResult <- {
        gridFS.files.update(
          BSONDocument("_id" -> file.id),
          BSONDocument("$set" -> BSONDocument("user" -> BSONObjectID(id)),
            "$set" -> BSONDocument("size" -> "original")))
      }
    } yield updateResult

    futureUpdate.map {
      case _ => Ok("xx")
    }.recover {
      case e => InternalServerError(e.getMessage())
    }
  }

如何添加另一个具有属性“大小”->“拇指”的文件,该文件具有相同的上传图像但已调整大小以适应小拇指?我这里有两个问题:

  • 如何在一次上传时将 2 个文件存储在 GridFS 中?
  • 如何在存储之前调整图像大小?

感谢您的回答。这是一个很好的方向。我一直在寻找 GridFS 的解决方案。这是我最终得到的结果:

  def saveAttachment(id: String) = Action.async(gridFSBodyParser(gridFS)) { request =>
  // here is the future file!
    val futureFile = request.body.files.head.ref
    // when the upload is complete, we add the article id to the file entry (in order to find the attachments of the article)
    val futureUpdate = for {
      file <- futureFile
      // here, the file is completely uploaded, so it is time to update the user
      updateResult <- {
        gridFS.files.update(
          BSONDocument("_id" -> file.id),
          BSONDocument("$set" -> BSONDocument("metadata" ->
                        BSONDocument("user" -> BSONObjectID(id),
                                      "size" -> "original"))))


        val iterator = gridFS.enumerate(file).run(Iteratee.consume[Array[Byte]]())
        iterator.flatMap {
          bytes => {
            // Create resized image
            val enumerator: Enumerator[Array[Byte]] = Enumerator.outputStream(
              out => {
                Image(bytes).bound(120, 120).writer(Format.JPEG).withCompression(90).write(out)
              }
            )

            val data = DefaultFileToSave(
              filename = file.filename,
              contentType = file.contentType,
              uploadDate = Some(DateTime.now().getMillis),
              metadata = file.metadata ++ BSONDocument(
                "user" -> BSONObjectID(id),
                "size" -> "thumb"
              )
            )

            Logger.warn(s"Saving resized image: [id=$id, metadata=${data.metadata}}]")
            gridFS.save(enumerator, data).map {
              image => Some(image)
            }
          }
        }
      }
    } yield updateResult

    futureUpdate.map {
      case _ => Ok("xx")
    }.recover {
      case e => InternalServerError(e.getMessage())
    }
  }
4

1 回答 1

2

解决方案非常简单,我使用scrimage进行图像处理,这是我的控制器:

// imports omitted

def upload = Authenticated.async(parse.multipartFormData) { request =>

  // some plumbing omitted

  request.body.file("photo") match {
    // validations omitted
    case Some(photo) =>
      val fileToSave = DefaultFileToSave(photo.filename, photo.contentType)
      val resizedFile = Image(photo.ref.file).fitToWidth(120).write
      val enumerator = Enumerator(resizedFile)
      gfs.save(enumerator, fileToSave) map {
        case file =>
          val id = file.id.asInstanceOf[BSONObjectID].stringify
          Ok(obj("files" -> Seq(obj(
            "id" -> id,
            "name" -> file.filename,
            "size" -> file.length,
            "url" -> routes.Photos.photo(id).url,
            "thumbnailUrl" -> routes.Photos.photo(id).url,
            "deleteUrl" -> "",
            "deleteType" -> "DELETE"
          ))))
      } recover {
        case e =>
          Logger.error(e.toString)
          InternalServerError("upload failed")
      }
    }
  }
}

请注意调整大小部分。

例如,您可以通过简单地复制基础文件并save使用调整大小的副本进行第二次调用来解决第一个问题。我手头没有完整的代码解决方案,所以如果您需要进一步的帮助,请随时询问详细信息。

于 2014-04-20T18:29:40.427 回答