适当解开akka http中的特征

时间:2018-03-31 14:23:34

标签: akka-http spray-json

我已经完成了关于SO的文档和许多问题,但仍然无法弄清楚我做错了什么。

我开始使用vanilla akka http g8模板,但我想使用特征而不是案例类来表示POST请求中的对象。

当使用案例类时,我的应用程序中的一切都很好,但是当我尝试实现特征时它失败了:

 [error] CollectionRoutes.scala:38: could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[collector.CollectorConfig]
 [error]               entity(as[CollectorConfig]) { config =>
 [error]                        ^
 [error] CollectionRoutes.scala:55: could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[collector.CollectorStep]
 [error]                 entity(as[CollectorStep]) { collstep =>
 [error]                          ^
 [error] CollectionRoutes.scala:77: could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[collector.CollectorConfig]
 [error]                 entity(as[CollectorConfig]) { config =>
 [error]                          ^
 [error] three errors found

这是我用来定义json格式的特性:

trait JsonSupport extends DefaultJsonProtocol {
      import spray.json._

      implicit val collectionTypeConverter = new EnumJsonConverter(CollectionType)

      implicit val actionPerformedJsonFormat = jsonFormat1(ActionPerformed)
      implicit val restCollectorStepFormat = jsonFormat3(RestCollectorStep)
      implicit object collectorStepFormat extends RootJsonFormat[CollectorStep] {
        def write(a: CollectorStep) = a match {
          case p: RestCollectorStep => p.toJson
        }
        def read(value: JsValue) =
          value.asJsObject.fields("collectionType") match {
            case JsString("Rest") => value.convertTo[RestCollectorStep]
          }
      }

      implicit val restCollectorConfigFormat = jsonFormat5(RestCollectorConfig)
      implicit object collectorConfigFormat extends RootJsonFormat[CollectorConfig] {
        def write(a: CollectorConfig) = a match {
          case p: RestCollectorConfig => p.toJson
        }
        def read(value: JsValue) =
          value.asJsObject.fields("collectionType") match {
            case JsString("Rest") => value.convertTo[RestCollectorConfig]
          }
      }

    }

这是定义我的路线的特征:

trait CollectionRoutes extends JsonSupport {

        import spray.json._
        implicit def system: ActorSystem
        lazy val log = Logging(system, classOf[CollectionRoutes])

        def collectorRegistryActor: ActorRef

        implicit lazy val timeout = Timeout(5.seconds) // usually we'd obtain the timeout from the system's configuration

        val settings = CorsSettings.defaultSettings.withAllowGenericHttpRequests(true)
        lazy val collectionRoutes: Route = cors(settings) {
          pathPrefix("createcollector") {
            concat(
              pathEnd {
                concat(
                  post {
                    entity(as[CollectorConfig]) { config =>
                      val collectorCreated: Future[CollectorRegistryActor.ActionPerformed] =
                        (collectorRegistryActor ? MakeCollector(config)).mapTo[CollectorRegistryActor.ActionPerformed]
                      onSuccess(collectorCreated) { created =>
                        complete(created.description)
                      }
                    }
                  }
                )
              }
            )
          } ~
            pathPrefix("reststep") {
              concat(
                pathEnd {
                  concat(
                    post {
                      entity(as[CollectorStep]) { collstep =>
                        val executionResult: Future[StepActor.StepResponse] = (collectorRegistryActor ? ExecuteStep(collstep)).mapTo[StepActor.StepResponse]
                        onSuccess(executionResult) { res =>
                          res match {
                            case StepActor.StepResult(step, response, result) => {
                              val res = (response :: result :: Nil).toJson.toString
                              complete(res)
                            }
                            case StepActor.StepError(step, error) => complete(error)
                          }
                        }
                      }
                    }
                  )
                }
              )
            } ~
            pathPrefix("restcollect") {
              concat(
                pathEnd {
                  concat(
                    post {
                      entity(as[CollectorConfig]) { config =>
                        val executionResult: Future[CollectorActor.CollectionResult] = (collectorRegistryActor ? ExecuteCollection(config)).mapTo[CollectorActor.CollectionResult]
                        onSuccess(executionResult) { response =>
                          complete(response.result)
                        }
                      }
                    }
                  )
                }
              )
            }
        }

      }

这就是这种特性的使用方式。

 object CollectionServer extends App with CollectionRoutes {

        implicit val system: ActorSystem = ActorSystem("CollectionServer")
        implicit val materializer: ActorMaterializer = ActorMaterializer()

        val collectorRegistryActor: ActorRef = system.actorOf(CollectorRegistryActor.props, "collectorRegistryActor")

        lazy val routes: Route = collectionRoutes

        Http().bindAndHandle(routes, "localhost", 9100)

        println(s"Server online at http://localhost:9100/")

        Await.result(system.whenTerminated, Duration.Inf)
      }

我感到困惑,因为我相信我已经以一种非常标准的方式设置了所有内容,但它并没有意识到这一点。

任何想法都赞赏 - 谢谢。

1 个答案:

答案 0 :(得分:0)

想出来:

我应该一直在扩展SprayJsonSupport而不是DefaultJsonProtocol

trait JsonSupport extends SprayJsonSupport {