Akka模块化消息发送功能

时间:2014-07-06 23:13:05

标签: scala akka spray

我正在使用Spray + Akka(我想说“框架”,但他们希望被称为“图书馆”)。我收到一个REST电话,然后我回复了一个回复。但是,我发现我的处理有点重复。当我从两个API收到POST请求时,这是两个块:

post {
                entity(as[JObject]) { company =>
                  if (AuthInfo.rejectedOrNot) {
                    val response = (secCompanyActor ? jObjectFromWeb(company))
                      .mapTo[TransOk]
                      .map(result => result.succeedOrNot match {
                      case true => (OK, "transaction successful")
                      case false => (BadRequest, result.errorMessage)
                    }).recover { case _ => (BadRequest, "An error has occurred! We will fix this")}
                    complete(response)

                  } else {
                    complete(Unauthorized, "Please use HTTP header to authorize this command.")
                  }
                }

另一个块非常相似,但唯一的区别是不是发送jObjectFromWeb(...),而是发送此消息:jObjectFromComputer(...)

我想创建一个函数,我传入消息然后从该函数发送消息,但Akka的消息不是TYPED!我理解来自无类型信息的哲学,我不是在争论什么,但我想要一个很好的解决方案。是的,一个解决方案是我传入一个像sendMessageToActor(actor, "jObjectFromWeb")这样的字符串,在实际的函数中,我使用模式匹配来发送相应的消息。

但它有点难看而且不是很模块化(如果我要发送10条消息怎么办?)。

有没有办法做到这一点?我对Java的反射并不熟悉,但如果我能通过字符串找到消息案例类/对象,那将是非常好的。


这是我的Akka演员实施方:

class SECCompanyActor extends Actor with ActorLogging {
  import com.mturk.tasks.SECcompany.SECCompanyProtocol._

  def receive = {

    case jObjectFromCasper(jObject) =>
      //Do some logic
      sender ! TransOk(result._1, result._2, result._3)

    case jObjectFromWeb(jObject) =>
      // Do some other logic
      sender ! TransOk(result._1, result._2, result._3)
  }

这是我的Akka消息:

object SECCompanyProtocol {
  case class jObjectFromCasper(jObject: JObject)
  case class TransOk(company: Option[Company.Company], succeedOrNot: Boolean, errorMessage: Option[String])
  case class jObjectFromWeb(jObject: JObject)
}

1 个答案:

答案 0 :(得分:1)

这个怎么样:

def doPost(messageConstructor: Company => AnyRef): Route = {
  entity(as[JObject]) { company =>
    if (AuthInfo.rejectedOrNot) {
      val response = (secCompanyActor ? messageConstructor(company))
        .mapTo[TransOk]
        .map(result => result.succeedOrNot match {
          case true => (OK, "transaction successful")
          case false => (BadRequest, result.errorMessage)
        }).recover { case _ => (BadRequest, "An error has occurred! We will fix this")}
      complete(response)
    } else {
      complete(Unauthorized, "Please use HTTP header to authorize this command.")
    }
  }
}    

post {
  doPost(jObjectFromWeb.apply)
}

正如您的评论所述,当jObjectFromWeb / jObjectFromComputer为案例类时,此方法有效。 jObjectFromWeb.apply对应于案例类的apply方法'伴随对象,它是为案例类自动创建的。更安全的类型设计将从单个特征继承两个案例类:

trait GenericJObject {
  val company: Company
}

case class JObjectFromWeb(override val company: Company) extends GenericJObject

case class JObjectFromComputer(override val company: Company) extends GenericJObject

def doPost(messageConstructor: Company => GenericJObject): Route = {
...
}

此外,对于可维护性以及理解您的代码以遵守Scala编码约定更好,其中类名以大写字母开头,否则有人可能会感到困惑并认为jObjectFromXXX是一种方法而不是案例类。