Scala与Mongodb实践2-----图片、日期的存储读取
目的:在IDEA中实现图片、日期等相关的类型在mongodb存储读取
- 主要是Scala和mongodb里面的类型的转换。Scala里面的数据编码类型和mongodb里面的存储的数据类型各个不同。存在类型转换。
- 而图片和日期的转换如下图所示。
1、日期的存取
- 简单借助java.until.Calendar即可。
1 2 3 | val ca=Calendar.getInstance() ca. set () ca.getTime |
- 有多种具体的格式等,再直接应用mgoDateTime等方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //显示各种格式 type MGODate = java.util.Date def mgoDate(yyyy: Int, mm: Int, dd: Int): MGODate = { val ca = Calendar.getInstance() ca. set (yyyy,mm,dd) ca.getTime() } def mgoDateTime(yyyy: Int, mm: Int, dd: Int, hr: Int, min: Int, sec: Int): MGODate = { val ca = Calendar.getInstance() ca. set (yyyy,mm,dd,hr,min,sec) ca.getTime() } def mgoDateTimeNow: MGODate = { val ca = Calendar.getInstance() ca.getTime } def mgoDateToString(dt: MGODate, formatString: String): String = { val fmt= new SimpleDateFormat(formatString) fmt.format(dt) } |
2、图片的存取(看图片大小,一般都是如下,大于16M的图片即采用GridFS,分别将图片的属性存储)
借助Akka的FileStream
将File(图片)===》Array[Byte]代码格式,图片在mongodb中显示形式binary
具体代码如下:
1 | FileStreaming.scala |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | package com.company.files import java.nio.file.Paths import java.nio._ import java.io._ import akka.stream.{Materializer} import akka.stream.scaladsl.{FileIO, StreamConverters} import scala.concurrent.{Await} import akka.util._ import scala.concurrent.duration._ object FileStreaming { def FileToByteBuffer(fileName: String, timeOut: FiniteDuration)( implicit mat: Materializer):ByteBuffer = { val fut = FileIO.fromPath(Paths. get (fileName)).runFold(ByteString()) { case (hd, bs) => hd ++ bs } (Await.result(fut, timeOut)).toByteBuffer } def FileToByteArray(fileName: String, timeOut: FiniteDuration)( implicit mat: Materializer): Array[Byte] = { val fut = FileIO.fromPath(Paths. get (fileName)).runFold(ByteString()) { case (hd, bs) => hd ++ bs } (Await.result(fut, timeOut)).toArray } def FileToInputStream(fileName: String, timeOut: FiniteDuration)( implicit mat: Materializer): InputStream = { val fut = FileIO.fromPath(Paths. get (fileName)).runFold(ByteString()) { case (hd, bs) => hd ++ bs } val buf = (Await.result(fut, timeOut)).toArray new ByteArrayInputStream(buf) } def ByteBufferToFile(byteBuf: ByteBuffer, fileName: String)( implicit mat: Materializer) = { val ba = new Array[Byte](byteBuf.remaining()) byteBuf. get (ba,0,ba.length) val baInput = new ByteArrayInputStream(ba) val source = StreamConverters.fromInputStream(() => baInput) //ByteBufferInputStream(bytes)) source.runWith(FileIO.toPath(Paths. get (fileName))) } def ByteArrayToFile(bytes: Array[Byte], fileName: String)( implicit mat: Materializer) = { val bb = ByteBuffer.wrap(bytes) val baInput = new ByteArrayInputStream(bytes) val source = StreamConverters.fromInputStream(() => baInput) //ByteBufferInputStream(bytes)) source.runWith(FileIO.toPath(Paths. get (fileName))) } def InputStreamToFile( is : InputStream, fileName: String)( implicit mat: Materializer) = { val source = StreamConverters.fromInputStream(() => is ) source.runWith(FileIO.toPath(Paths. get (fileName))) } } |
- Helpers.scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | package com.company.lib import java.util.concurrent.TimeUnit import scala.concurrent.Await import scala.concurrent.duration.Duration import java.text.SimpleDateFormat import java.util.Calendar import org.mongodb.scala._ object Helpers { implicit class DocumentObservable[C](val observable: Observable[Document]) extends ImplicitObservable[Document] { override val converter: (Document) => String = (doc) => doc.toJson } implicit class GenericObservable[C](val observable: Observable[C]) extends ImplicitObservable[C] { override val converter: (C) => String = (doc) => doc.toString } trait ImplicitObservable[C] { val observable: Observable[C] val converter: (C) => String def results(): Seq[C] = Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS)) def headResult() = Await.result(observable.head(), Duration(10, TimeUnit.SECONDS)) def printResults(initial: String = "" ): Unit = { if (initial.length > 0) print(initial) results(). foreach (res => println(converter(res))) } def printHeadResult(initial: String = "" ): Unit = println(s "${initial}${converter(headResult())}" ) } type MGODate = java.util.Date def mgoDate(yyyy: Int, mm: Int, dd: Int): MGODate = { val ca = Calendar.getInstance() ca. set (yyyy,mm,dd) ca.getTime() } def mgoDateTime(yyyy: Int, mm: Int, dd: Int, hr: Int, min: Int, sec: Int): MGODate = { val ca = Calendar.getInstance() ca. set (yyyy,mm,dd,hr,min,sec) ca.getTime() } def mgoDateTimeNow: MGODate = { val ca = Calendar.getInstance() ca.getTime } def mgoDateToString(dt: MGODate, formatString: String): String = { val fmt= new SimpleDateFormat(formatString) fmt.format(dt) } } |
- Model.scala
模型中包含了两个具体的模型Person和Address,二者是包含关系,具体模型内含存取方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | package com.company.demo import org.mongodb.scala._ import bson._ import java.util.Calendar import com.company.files._ import akka.stream.ActorMaterializer object Models { //Model可存在在不同的模型,下面存在一个拥有代表性的模型Person case class Address( //Scala中的字段类型,且String的默认参数是“” city: String = "" , zipcode: String = "" ) { def toDocument: Document = bson.Document( //bson.Document是bson包里面的Document,其他包内有不同的Document "city" -> city, "zipcode" -> zipcode ) def fromDocument(doc: Document): Address = this .copy( city = doc.getString( "city" ), zipcode = doc.getString( "zipcode" ) ) } //这是日期的设置 val ca = Calendar.getInstance() ca. set (2001,10,23) val defaultDate = ca.getTime case class Person ( lastName: String = "Doe" , firstName: String = "John" , age: Int = 1, phones: List[String] = Nil, address: List[Address] = Nil, birthDate: java.util.Date = defaultDate, picture: Array[Byte] = Array() ) { ctx => def toDocument: Document = { var doc = bson.Document( "lastName" -> ctx.lastName, "firstName" -> ctx.firstName, "age" -> ctx.age, "birthDate" -> ctx.birthDate ) if (ctx.phones != Nil) doc = doc + ( "phones" -> ctx.phones) if (ctx.address != Nil) doc = doc + ( "address" -> ctx.address.map(addr => addr.toDocument)) if (!ctx.picture.isEmpty) doc = doc + ( "picture" -> ctx.picture) doc } import scala.collection.JavaConverters._ def fromDocument(doc: Document): Person = { //keySet val ks = doc.keySet ctx.copy( lastName = doc.getString( "lastName" ), firstName = doc.getString( "firstName" ), age = doc.getInteger( "age" ), phones = { doc. get ( "phones" ).asInstanceOf[Option[BsonArray]] match { case Some(barr) => barr.getValues.asScala.toList.map(_.toString) case None => Nil } }, address = { if (ks.contains( "address" )) { doc. get ( "address" ).asInstanceOf[Option[BsonArray]] match { case Some(barr) => barr.getValues.asScala.toList.map ( ad => Address().fromDocument(ad.asDocument()) ) case None => Nil } } else Nil }, picture = { if (ks.contains( "picture" )) { doc. get ( "picture" ).asInstanceOf[Option[BsonBinary]] match { case Some(ba) => ba.getData case None => Array() } } else Array() } ) } //在控制台显示的格式。 def toSink()( implicit mat: ActorMaterializer) = { println(s "LastName: ${ctx.lastName}" ) println(s "firstName: ${ctx.firstName}" ) println(s "age: ${ctx.age}" ) println(s "phones: ${ctx.phones}" ) println(s "address ${ctx.address}" ) if (!ctx.picture.isEmpty) { val path = s "/img/${ctx.firstName}.jpg" FileStreaming.ByteArrayToFile(ctx.picture,path) println(s "picture saved to: ${path}" ) } } } } |
- PersonCRUD.scala简单测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | package com.company.demo import org.mongodb.scala._ import bson._ import java.util.Calendar import scala.collection.JavaConverters._ import com.company.lib.Helpers._ import com.company.files.FileStreaming._ import akka.actor._ import akka.stream._ import scala.concurrent.duration._ import scala.util._ object PersonCRUD extends App { import Models._ implicit val system = ActorSystem() implicit val ec = system.dispatcher implicit val mat = ActorMaterializer() // or provide custom MongoClientSettings val settings: MongoClientSettings = MongoClientSettings.builder() .applyToClusterSettings(b => b.hosts(List( new ServerAddress( "localhost" )).asJava)) .build() val client: MongoClient = MongoClient(settings) val mydb = client.getDatabase( "mydb" ) val mytable = mydb.getCollection( "personal" ) val susan = Person( lastName = "Wang" , firstName = "Susan" , age = 18, phones = List( "137110998" , "189343661" ), address = List( Address( "Sz" , "101992" ), Address(city = "gz" , zipcode= "231445" ) ), birthDate = mgoDate(2001,5,8), picture = FileToByteArray( "/img/sc.jpg" ,3 seconds) ) /* val futResult = mytable.insertOne(susan.toDocument).toFuture() futResult.onComplete { case Success(value) => println(s"OK! ${value}") case Failure(err) => println(s"Boom!!! ${err.getMessage}") } scala.io.StdIn.readLine() */ <br> mytable.find().toFuture().andThen { case Success(ps) => ps. foreach (Person().fromDocument(_).toSink()) case Failure(err) => println(s "ERROR: ${err.getMessage}" ) } scala.io.StdIn.readLine() system.terminate() } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)