我正在使用 scala 3.3 和 Akka actor 构建 Akka HTTP 应用程序。
star, planet or moon
当在对象中创建a 时StarRegistry
,我希望它的值暂时存储在registry
函数的 map 变量中map: Map[String, Set[HeavenlyBody]]
。
应该map
存储如下所示的值,每个参数都有自己的类型,如下所述:
"stars" -> Set[CreateStar],
"planets" -> Set[CreatePlanet],
"moons" -> Set[CreateMoon],
脚本中starRoutes
包含 API。
APIstars
路由用于创建新星星以及获取map
上述存储中的所有星星。
当获取 GET API 路由时,我希望 api从上面的函数中stars
获取该字段stars
中存储的所有内容。stars
registry
map
功能的描述与和功能star
的描述类似。moon
planet
当前代码给出错误:
Type Mismatch Error: D:\Studio\WORK\akka\AKKA-HTTP\scala-akka-http-interstellar-IoT\src\main\scala\com\example\StarRegistry.scala:
replyTo ! Stars(map.get("stars").toSeq)
Found: Seq[Set[com.example.HeavenlyBody]]
Required: Seq[com.example.CreateStar]
Type Mismatch Error: D:\Studio\WORK\akka\AKKA-HTTP\scala-akka-http-interstellar-IoT\src\main\scala\com\example\StarRegistry.scala:199:45
replyTo ! Planets(map.get("planets").toSeq)
Found: Seq[Set[com.example.HeavenlyBody]]
Required: Seq[com.example.CreatePlanet]
Type Mismatch Error: D:\Studio\WORK\akka\AKKA-HTTP\scala-akka-http-interstellar-IoT\src\main\scala\com\example\StarRegistry.scala:213:41
replyTo ! Moons(map.get("moons").toSeq)
Found: Seq[com.example.HeavenlyBody]
Required: Seq[com.example.CreateMoon]
我当前的代码如下所示。
提前感谢您的帮助!
StarRegistry.scala:
sealed trait HeavenlyBody
final case class CreateStar(id: String, name: String, location: String, size: Option[Size]) extends HeavenlyBody
final case class CreatePlanet(id: String, name: String, location: String, size: Option[Size]) extends HeavenlyBody
final case class CreateMoon(id: String, name: String, location: String, size: Option[Size]) extends HeavenlyBody
final case class Stars(stars: immutable.Seq[CreateStar])
final case class Planets(planets: immutable.Seq[CreatePlanet])
final case class Moons(moons: immutable.Seq[CreateMoon])
final case class Size(radius: Long)
object StarRegistry {
// actor protocol
sealed trait Command
final case class GetStars(replyTo: ActorRef[Stars]) extends Command
final case class NewStar(star: CreateStar, replyTo: ActorRef[ActionPerformed]) extends Command
final case class GetPlanets(replyTo: ActorRef[Planets]) extends Command
final case class NewPlanet(planet: CreatePlanet, replyTo: ActorRef[ActionPerformed]) extends Command
final case class GetMoons(replyTo: ActorRef[Moons]) extends Command
final case class NewMoon(moon: CreateMoon, replyTo: ActorRef[ActionPerformed]) extends Command
final case class ActionPerformed(description: String)
def apply(): Behavior[Command] = registry(Map("stars" -> Set.empty, "planets" -> Set.empty, "moons" -> Set.empty))
private def registry(map: Map[String, Set[HeavenlyBody]]): Behavior[Command] =
Behaviors.receiveMessage {
case GetStars(replyTo) =>
replyTo ! Stars(map.get("stars").toSeq)
Behaviors.same
case NewStar(star, replyTo) =>
replyTo ! ActionPerformed(s"Star '${star.name}' created!")
registry(map("stars") += star)
case GetPlanets(replyTo) =>
replyTo ! Planets(map.get("planets").toSeq)
Behaviors.same
case NewPlanet(planet, replyTo) =>
replyTo ! ActionPerformed(s"Planet '${planet.name}' created!")
registry(map("planets") += planet)
case GetMoons(replyTo) =>
replyTo ! Moons(map.get("moons").toSeq)
Behaviors.same
case NewMoon(moon, replyTo) =>
replyTo ! ActionPerformed(s"Moon '${moon.name}' created!")
registry(map("moons") += moon)
}
}
jsonFormats.scala:
...
...
object JsonFormats {
import DefaultJsonProtocol._
implicit val sizeJsonFormat: RootJsonFormat[Size] = jsonFormat1(Size.apply)
implicit val createStarJsonFormat: RootJsonFormat[CreateStar] = jsonFormat4(CreateStar.apply)
implicit val createPlanetJsonFormat: RootJsonFormat[CreatePlanet] = jsonFormat4(CreatePlanet.apply)
implicit val createMoonJsonFormat: RootJsonFormat[CreateMoon] = jsonFormat4(CreateMoon.apply)
implicit val starsJsonFormat: RootJsonFormat[Stars] = jsonFormat1(Stars.apply)
implicit val planetsJsonFormat: RootJsonFormat[Planets] = jsonFormat1(Planets.apply)
implicit val moonsJsonFormat: RootJsonFormat[Moons] = jsonFormat1(Moons.apply)
implicit val actionPerformedJsonFormat: RootJsonFormat[ActionPerformed] = jsonFormat1(ActionPerformed.apply)
}
明星路线.scala:
class StarRoutes(starRegistry: ActorRef[StarRegistry.Command])(implicit val system: ActorSystem[_]) {
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import JsonFormats._ //#import-json-formats
def getStars(): Future[Stars] =
starRegistry.ask(GetStars.apply)
def createStar(star: CreateStar): Future[ActionPerformed] =
starRegistry.ask(NewStar(star, _))
def getPlanets(): Future[Planets] =
starRegistry.ask(GetPlanets.apply)
def createPlanet(planet: CreatePlanet): Future[ActionPerformed] =
starRegistry.ask(NewPlanet(planet, _))
def getMoons(): Future[Moons] =
starRegistry.ask(GetMoons.apply)
def getMoon(name: String): Future[GetMoonResponse] =
starRegistry.ask(GetMoon(name, _))
val starRoutes: Route =
...
pathPrefix("stars") {
concat(
pathEnd {
concat(
get {
complete(getStars())
},
post {
entity(as[CreateStar]) { star =>
onSuccess(createStar(star)) { performed =>
complete((StatusCodes.Created, performed))
}
}
})
},
}
...
pathPrefix("planets") {
concat(
pathEnd {
concat(
get {
complete(getPlanets())
},
post {
entity(as[CreatePlanet]) { planet =>
onSuccess(createPlanet(planet)) { performed =>
complete((StatusCodes.Created, performed))
}
}
})
},
...
pathPrefix("moons") {
concat(
pathEnd {
concat(
get {
complete(getMoons())
},
post {
entity(as[CreateMoon]) { moon =>
onSuccess(createMoon(moon)) { performed =>
complete((StatusCodes.Created, performed))
}
}
})
}