spray-scan , spray-client 与 spray-routing 简单的订阅系统

具体

 

http://spray.io/documentation/1.2.3/spray-client/

1.构建service

添加依赖

 

 

name:="demo10"


scalaVersion  := "2.11.6"

scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8")

libraryDependencies ++= {
  val akkaV = "2.3.9"
  val sprayV = "1.3.3"
  Seq(
    "io.spray"            %%  "spray-can"         % sprayV,
    "io.spray"            %%  "spray-routing"     % sprayV,
    "io.spray"            %%  "spray-client"      % sprayV,
    "io.spray"            %%  "spray-util"        % sprayV,
    "io.spray"            %%  "spray-httpx"       % sprayV,
    "io.spray"            %   "spray-json_2.10"   % "1.3.2",
    "io.spray"            %%  "spray-http"        % sprayV,
    "io.spray"            %%  "spray-testkit"     % sprayV   % "test",
    "com.typesafe.akka"   %%  "akka-actor"        % akkaV,
    "com.typesafe.akka"   %%  "akka-testkit"      % akkaV    % "test",
    "org.specs2"          %%  "specs2-core"       % "2.3.11" % "test"
  )
}


 

 

 

 

编写service的关键就是Directive,我们说过Directive的作用,下面我们侧重操作Directive的组合

 

我们通过 | , & 来简单的组合

  val rightPath = post & authenticate(BasicAuth(authenticator _, realm = "secure site")) & parameters('id.as[Int]).as(Order)

我们要求请求必须是post  且 带id参数的认证请求,

所以整个routing的配置如下

 

  def authenticator(userPass: Option[UserPass]): Future[Option[String]] = Future {
       //检查用户
      if (userPass.exists(up => up.user == "admin" && up.pass == "admin")) Some(userPass.get.user)
      else None
    }
  val rightPath = post & authenticate(BasicAuth(authenticator _, realm = "secure site")) & parameters('id.as[Int]).as(Order)

  val route = sealRoute{
    path("orders"){
      rightPath{ (name:String,order:Order) =>
        complete(<H1>Hello ${name}! Welcome to our site! Your order => ${order.toString}</H1>)
      }
    }
  }


我们用curl测试一下

整个service的源码:

import akka.actor.{Props, ActorSystem}
import akka.io.IO
import akka.util.Timeout
import shapeless.Zipper.Put
import spray.can.Http
import spray.routing._
import spray.http._
import spray.routing.authentication.{UserPass, BasicAuth}
import scala.concurrent.duration._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global



object ActorTest5 extends App{

  implicit val system = ActorSystem("mySystem")

  val se = system.actorOf(Props[MyService2])

  implicit val timeout = Timeout(5.seconds)

  IO(Http) ! Http.Bind(se,interface = "localhost",port=8080)

}
case class Order(id:Int)

class MyService2 extends HttpServiceActor {


  def authenticator(userPass: Option[UserPass]): Future[Option[String]] = Future {
       //检查用户
      if (userPass.exists(up => up.user == "admin" && up.pass == "admin")) Some(userPass.get.user)
      else None
    }
  val rightPath = post & authenticate(BasicAuth(authenticator _, realm = "secure site")) & parameters('id.as[Int]).as(Order)

  val route = sealRoute{
    path("orders"){
      rightPath{ (name:String,order:Order) =>
        complete(<H1>Hello ${name}! Welcome to our site! Your order => ${order.toString}</H1>)
      }
    }
  }


  def receive = runRoute(route)
}



2.构建client端

第一步是提供ActorSystem

  implicit val system = ActorSystem()
  import system.dispatcher

 

这里我们使用"管道"的方式请求

  A pipeline of type HttpRequest => Future[HttpResponse]


从签名就可以知道大概意思了

  val pipeline: HttpRequest => Future[String] = (
      addCredentials(BasicHttpCredentials("admin", "admin"))
      ~> encode(Gzip)
      ~> sendReceive
      ~> decode(Deflate)
      ~> unmarshal[String]
    )


这里需要注意的是~>函数的组合 相当于haskell的客串化 >>=

我们看看他是如何实现的

  implicit class WithTransformerConcatenation[A, B](f: A ⇒ B) extends (A ⇒ B) {
    def apply(input: A) = f(input)
    def ~>[AA, BB, R](g: AA ⇒ BB)(implicit aux: TransformerAux[A, B, AA, BB, R]) =
      new WithTransformerConcatenation[A, R](aux(f, g))
  }

这里使用了隐式转换
将函数转换成WithTransformerConcatenation,主要是添加~>的方法,apply中把函数的入参"处理了"-----f(input) 接着通过~>把结果传递给下一个函数

 

整个源码:

 

 

import akka.actor.ActorSystem
import akka.io.IO
import scala.concurrent.Future
import spray.can.Http
import spray.http._
import spray.json.DefaultJsonProtocol
import spray.httpx.encoding.{Gzip, Deflate}
import spray.httpx.SprayJsonSupport._
import spray.client.pipelining._
import akka.pattern.ask

case class Order1(id: Int)

object JsonConver extends DefaultJsonProtocol {
  implicit val orderFormat = jsonFormat1(Order1)
}


object ActorTest1 extends App{
  import JsonConver._
  implicit val system = ActorSystem()
  import system.dispatcher

  val pipeline: HttpRequest => Future[String] = (
      addCredentials(BasicHttpCredentials("admin", "admin"))
      ~> encode(Gzip)
      ~> sendReceive
      ~> decode(Deflate)
      ~> unmarshal[String]
    )

  val response: Future[String] = pipeline(Post("http://localhost:8080/orders?id=2001"))

  response.onSuccess{
    case res => println(res)
  }
}


 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值