如何在没有GridFS的情况下从Play网页上传图像并将其存储在MongoDB中?
我有一个简单的网站,我可以上传文章,并显示给网站访问者。文章存储在MongoDB中。 我决定添加一个简单的功能,允许管理员在文章顶部插入一个图像。我希望这个图像存储在MongoDB的同一个文章文档中。如何在没有GridFS的情况下从Play网页上传图像并将其存储在MongoDB中?,mongodb,scala,playframework,Mongodb,Scala,Playframework,我有一个简单的网站,我可以上传文章,并显示给网站访问者。文章存储在MongoDB中。 我决定添加一个简单的功能,允许管理员在文章顶部插入一个图像。我希望这个图像存储在MongoDB的同一个文章文档中。 无需使用GridFS,最简单的实现方法是什么?您可以对图像进行Base64编码并将其添加到文档中。请注意,MongoDB BSON文档的最大大小为16 MB。以下是我的答案,因此该解决方案适用于所有需要相同内容的人。当然,它也有其局限性,比如最大图像大小为16Mb,但在许多情况下,它并不相关 我的
无需使用GridFS,最简单的实现方法是什么?您可以对图像进行Base64编码并将其添加到文档中。请注意,MongoDB BSON文档的最大大小为16 MB。以下是我的答案,因此该解决方案适用于所有需要相同内容的人。当然,它也有其局限性,比如最大图像大小为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
方法将图片数据插入到特定的文章文档中。作为输入,它获取字节数组并使用二进制
类型对其进行编码
picture
方法从文章文档中检索picture原始字节
现在,为
标签上传图片文件和检索图片的相关控制器方法:
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]))
}
}
此方法用于将文章视图上的图像呈现为
标记,如下所示:
路由
文件的相关部分:
POST /updatePicture controllers.MainController.updatePicture
GET /picture/:title controllers.MainController.picture(title:String)
这不太实际。提供静态内容不应该如此昂贵。正如许多文章中已经提到的,它适合很多情况,并且具有MongoDB已经给您带来的好处。如果需要,还可以缓存图像数据响应,这并不难。很公平,很高兴您能帮助自己。对我来说,这有两个主要好处:1)无需将图像存储在文件系统中-因此我不需要为此实现更多代码。同样值得怀疑的是,来自FS的服务是否真的比使用响应缓存的方式快得多。2) 如果我需要迁移到另一个实例,我只需转储mongoDB,在另一个实例上进行转储,我就完成了。我指的是内存使用。它是mongodb的宝藏,把它浪费在可以作为二进制流使用的地方感觉有点时髦,但是是的,如果它对你有用,那就太好了。是的,我在下面的回答中概述了这个解决方案。不确定MongoDB类型是否使用base64编码,但可能使用base64编码。