我一直在尝试在scala中的play framework 2.5上使用websocket。 现在,我想交换多种消息类型。
但是,当客户端通过websocket发送json时,我会收到以下错误。
我是否必须选择不同的方式来交换多种消息类型?
缺少某些东西还是有更简单的方法?
[error] a.a.OneForOneStrategy - {"sort":"post", "to":"receiver","message":"Test"} (of class play.api.libs.json.JsObject)
scala.MatchError: {"sort":"post", "to":"receiver","message":"Test"} (of class play.api.libs.json.JsObject)
at controllers.MessageController$MessageActor$$anonfun$receive$1.applyOrElse(MessageController.scala:72)
at akka.actor.Actor$class.aroundReceive(Actor.scala:514)
at controllers.MessageController$MessageActor.aroundReceive(MessageController.scala:63)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:527)
at akka.actor.ActorCell.invoke(ActorCell.scala:496)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:257)
at akka.dispatch.Mailbox.run(Mailbox.scala:224)
at akka.dispatch.Mailbox.exec(Mailbox.scala:234)
at akka.dispatch.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at akka.dispatch.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
models.scala
abstract class WSMessageIn()
// Classes for input
case class PostMessage(
sort: String = "post",
to: String,
...
message: Option[String] = None
) extends WSMessageIn
object PostMessage {
implicit val postMessageFormat = Json.format[PostMessage]
}
case class MessageFromIn(
sort: String = "receive",
from: String,
...
message: Option[String] = None
) extends WSMessageIn
object MessageFromIn {
implicit val messageFromInFormat = Json.format[MessageFromIn]
}
object WSMessageIn {
implicit def json2object(value: JsValue): WSMessageIn = {
(value \ "sort").as[String] match {
case "post" => value.as[PostMessage]
case "receive" => value.as[MessageFromIn]
}
}
implicit def object2json(in: WSMessageIn): JsValue = {
in match {
case in: PostMessage => Json.toJson(in)
case in: MessageFromIn => Json.toJson(in)
}
}
}
MessageController.scala
class MessageController @Inject() (
silhouette: Silhouette[DefaultEnv],
..
implicit val system: ActorSystem,
implicit val materializer: Materializer)
extends Controller {
class MessageActor(out: ActorRef) extends Actor {
override def receive = {
case message: JsValue =>
message match { // !!The error occurs here
case message: PostMessage =>
...
case message: MessageFromIn =>
...
}
}
}
object MessageActor {
def props(out: ActorRef) = Props(new MessageActor(out))
}
implicit val messageFlowTransformer = MessageFlowTransformer.jsonMessageFlowTransformer[JsValue, JsValue]
def socket() = WebSocket.acceptOrResult[JsValue, JsValue] { request =>
implicit val req = Request(request, AnyContentAsEmpty)
silhouette.SecuredRequestHandler { securedRequest =>
Future.successful(HandlerResult(Ok, Some(securedRequest.identity)))
}.map {
case HandlerResult(r, Some(user)) => Right(ActorFlow.actorRef(out => MessageActor.props(out)))
case HandlerResult(r, None) => Left(r)
}
}
}
答案 0 :(得分:0)
原样:WebSocket.acceptOrResult[JsValue, JsValue]
您希望您的websocket接收JsValue
。
这似乎与MessageActor
中的代码匹配:
override def receive = {
case message: JsValue => // ...
}
但是,如果没有您的干预,您不应期望从JsValue
转换为WSMessageIn
。
你能做的只是:
override def receive = {
case message: JsValue =>
WSMessageIn.json2object(message) match {
case message: PostMessage =>
...
case message: MessageFromIn =>
...
}
}
您可能期望进行隐式转换,您可以通过向编译器提示(即说出您期望的内容)来获取它:
override def receive = {
case message: JsValue =>
(message: WSMessageIn) match {
case message: PostMessage =>
...
case message: MessageFromIn =>
...
}
}
注意:您可以将abstract class WSMessageIn()
变为:sealed trait WSMessageIn