【问题标题】:How to upload an image from Play webpage and store it in MongoDB without GridFS?如何在没有 GridFS 的情况下从 Play 网页上传图像并将其存储在 MongoDB 中?
【发布时间】:2017-09-05 13:55:01
【问题描述】:

我有一个简单的网站,我可以在其中上传文章并将其展示给网站访问者。文章存储在 MongoDB 中。 我决定添加一个简单的功能,允许管理员在文章顶部插入图像。我希望这张图片存储在同一篇文章文档中的 MongoDB 中。 在不需要使用 GridFS 的情况下实现这一目标的最简单方法是什么?

【问题讨论】:

  • 不太实用。提供静态内容不应该那么昂贵。
  • 正如很多文章中已经提到的那样 - 它适用于很多情况,并且具有 MongoDB 已经为您提供的好处。如果需要,还可以缓存带有图像数据的响应,这并不难。
  • 很公平,很高兴你帮助了自己。
  • 对我来说有两个主要好处:1)不需要在文件系统中存储图像 - 所以我不需要为此实现更多代码。同样值得怀疑的是,从 FS 提供服务是否真的比通过响应缓存提供服务要快得多。 2)如果我需要迁移到其他实例 - 我只是转储 mongoDB,在其他实例上滚动转储就完成了。
  • 我的错,首先没有正确表达我的担忧。我指的是内存使用情况。它是 mongodb 的宝藏,把它浪费在可以用作二进制流的东西上感觉有点奢侈,但是,是的,如果它对你有用,那就太好了。

标签: mongodb scala playframework


【解决方案1】:

这是我的答案,因此为所有需要相同东西的人概述了解决方案。它当然有其局限性,例如最大图像大小为 16Mb,但在很多情况下它并不相关。

我的 DAO 的相关部分:

trait DocumentService {
  ....
  def updatePicture(data:Array[Byte], title:String)(implicit ec:ExecutionContext):Future[UpdateResult]
  def picture(title:String)(implicit ec:ExecutionContext):Future[Option[Array[Byte]]]
}

这里title是文章的标题,它是唯一的,在文章提取和特定文章的所有相关操作中用作键。

实施:

package services

import javax.inject.Singleton

import com.mongodb.client.result.UpdateResult
import model.Annotation
import org.bson.types.Binary
import org.mongodb.scala.bson.collection.immutable.Document
import org.mongodb.scala.{MongoClient}
import org.mongodb.scala.model.Filters._
import org.mongodb.scala.model.Updates._
import _root_.scala.concurrent.{ExecutionContext, Future}

/**
  * Created by Alex on 7/13/2016.
  */
@Singleton
class MongoDocumentService extends DocumentService{
  val mongoClient:MongoClient = MongoClient()
  val db = mongoClient.getDatabase("test")
  .....
  override def updatePicture(data: Array[Byte], title:String)(implicit ec: ExecutionContext): Future[UpdateResult] = {
    val collection = db.getCollection("items")
    val update = set("picture.data", new Binary(data))
    collection.updateOne(equal("title", title), update).toFuture().map(sx => sx.head)
  }

  override def picture(title: String)(implicit ec: ExecutionContext): Future[Option[Array[Byte]]] = {
    val collection = db.getCollection("items")
    collection.find(equal("title", title)).first()
      .toFuture()
      .recoverWith{case e:Throwable => {println(e); Future.failed(e)}}
      .map{seq => if(seq.isEmpty) None else seq.head.get("picture").map(p => p.asDocument().get("data")).map(r => r.asBinary().getData)}
  }
}

updatePicture 方法将图片数据插入到特定的文章文档中。作为输入,它获取字节数组并使用Binary 类型对其进行编码。

picture 方法从文章文档中检索图片原始字节。

现在为<img src="...">标签提供图片文件上传和图片检索的相关控制器方法:

def updatePicture = AdminAction.async(parse.multipartFormData){implicit request =>
    request.body.file("contentField").fold(Future.successful(Redirect(routes.MainController.index())))
    {filePart =>
      val tempFile = new File("./temp.txt");
      filePart.ref.moveTo(tempFile, true)
      val in = new FileInputStream(environment.getFile("./temp.txt"))
      val content = Stream.continually(in.read()).takeWhile(_ != -1).map(_.toByte).toArray
      val formOtherFields = request.body.asFormUrlEncoded
      val title = formOtherFields("titleField").head
      documentService.updatePicture(content, title).map(
        r => {
          in.close()
          tempFile.delete()
          Redirect(routes.MainController.index())
        }
      )
    }
  }

此控制器操作处理图像文件上传,它使用多部分表单数据解析器访问文件数据并将其提供给上面显示的相关 DAO 方法。

def picture(title:String) = Action.async{implicit request =>
    documentService.picture(title).map{
      case r => Ok(r.getOrElse(Array.empty[Byte]))
    }
  }

此方法用于在文章视图上将图像呈现为<img src="..."> 标签,如下所示: <img src="/picture/@{document.get("title").get.asString().getValue}"/>

routes 文件的相关部分:

POST    /updatePicture              controllers.MainController.updatePicture
GET     /picture/:title             controllers.MainController.picture(title:String)

【讨论】:

    【解决方案2】:

    您可以对图像进行 base 64 编码并将其添加到文档中。请注意,最大 MongoDB BSON 文档大小为 16 MB。

    【讨论】:

    • 是的,我在下面的答案中概述了这个解决方案。不确定Binary MongoDB 类型是否使用 base64 编码,但可能确实如此。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    • 2012-04-24
    相关资源
    最近更新 更多