要求:spray.httpx.marshalling.ToResponseMarshallable 错误

required: spray.httpx.marshalling.ToResponseMarshallable Error

嘿,我对 Spray 和反应式还很陌生 mongo。

我正在尝试 return 作为 json 的结果列表,但我在将结果转换为 json 列表时遇到了一些问题。

这是我的模型

import reactivemongo.bson.BSONDocumentReader
import reactivemongo.bson.BSONObjectID
import reactivemongo.bson.Macros

case class Post(id: BSONObjectID, likes: Long, message: String, object_id: String, shares: Long)

object Post {
  implicit val reader: BSONDocumentReader[Post] = Macros.reader[Post]
}

Mongo方法

 def getAll(): Future[List[Post]] ={
 val query = BSONDocument(
  "likes" -> BSONDocument(
    "$gt" -> 27))
   collection.find(query).cursor[Post].collect[List]()
}

这是路线

val route1 =
  path("posts") {
    val res: Future[List[Post]]= mongoService.getAll()
    onComplete(res) {
      case Success(value) => complete(value)
      case Failure(ex)    => complete(ex.getMessage)
    }
  }    

错误

type mismatch; found : List[com.example.model.Post] required: spray.httpx.marshalling.ToResponseMarshallable

谢谢,

三木

您需要定义 Post 将如何序列化,这可以通过 spray-json 协议来实现(请参阅 docs 了解更多详细信息)。这样做很容易,但在此之前,您还需要为 BSONObjectId 类型定义一种格式,因为在 spray-json 中没有对该类型的内置支持(或者,如果 object_idBSONObjectId 的字符串表示形式,请考虑从 Post class 中删除 id 属性 或将其更改为字符串):

// necessary imports
import spray.json._
import spray.httpx.SprayJsonSupport._

implicit object BSONObjectIdProtocol extends RootJsonFormat[BSONObjectID] {
    override def write(obj: BSONObjectID): JsValue = JsString(obj.stringify)
    override def read(json: JsValue): BSONObjectID = json match {
      case JsString(id) => BSONObjectID.parse(id) match {
        case Success(validId) => validId
        case _ => deserializationError("Invalid BSON Object Id")
      }
      case _ => deserializationError("BSON Object Id expected")
    }
}

现在,我们可以为 Post class:

定义实际的协议
object PostJsonProtocol extends DefaultJsonProtocol {
    implicit val format = jsonFormat5(Post.apply)
}

此外,我们还需要确保在范围内定义了格式:

import PostJsonProtocol._

现在,一切都将按预期编译。

还有一件事:看看喷的docs about the DSL structure。您的 mongoService.getAll() 不在 complete 块内,这可能无法反映您的意图。这还不是问题,但如果您的路线变得更复杂,则可能会成为问题。要解决此问题,只需将 future 放入 onComplete 调用中或使其变得懒惰:

val route1 =
  path("posts") {
    onComplete(mongoService.getAll()) {
      case Success(value) => complete(value)
      case Failure(ex)    => complete(ex.getMessage)
    }
  }