永利棋牌官方下载-www.55402.com-永利国际唯一指定官网

永利棋牌官方下载提供最新最好玩的真人游戏,www.55402.com是澳门国际娱乐平台官方网站唯一授权会员登录手机版,www.316net,www.366net,516.net,626.net,766.net,www.565.net,www.16.net,bwin62.com,bwin180.com,永利国际唯一指定官网为新老顾客提供更多的精彩娱乐项目,,所有的玩家都可以得到注册送体验金的巨大福利是设身处地为玩家量身订造的经典网站。

Akka(30): Http:High-Level-Api,Routing DSL

  在上篇我们介绍了Akka-http Low-Level-Api。实际上那么些Api提供了Server对步入的Http-requests举行拍卖及影响的自定义Flow只怕转变函数的交接分界面。我们看看上面官方文档给出的事例:

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpMethods._
import akka.http.scaladsl.model._
import akka.stream.ActorMaterializer
import scala.io.StdIn

object WebServer {

  def main(args: Array[String]) {
    implicit val system = ActorSystem()
    implicit val materializer = ActorMaterializer()
    // needed for the future map/flatmap in the end
    implicit val executionContext = system.dispatcher

    val requestHandler: HttpRequest => HttpResponse = {
      case HttpRequest(GET, Uri.Path("/"), _, _, _) =>
        HttpResponse(entity = HttpEntity(
          ContentTypes.`text/html(UTF-8)`,
          "<html><body>Hello world!</body></html>"))

      case HttpRequest(GET, Uri.Path("/ping"), _, _, _) =>
        HttpResponse(entity = "PONG!")

      case HttpRequest(GET, Uri.Path("/crash"), _, _, _) =>
        sys.error("BOOM!")

      case r: HttpRequest =>
        r.discardEntityBytes() // important to drain incoming HTTP Entity stream
        HttpResponse(404, entity = "Unknown resource!")
    }

    val bindingFuture = Http().bindAndHandleSync(requestHandler, "localhost", 8080)
    println(s"Server online at http://localhost:8080/nPress RETURN to stop...")
    StdIn.readLine() // let it run until user presses return
    bindingFuture
      .flatMap(_.unbind()) // trigger unbinding from the port
      .onComplete(_ => system.terminate()) // and shutdown when done
  }
}

  大家看出下边例子里的requestHandler函数用情势相配格局对可能收到的HttpRequest举办了相关HttpResponse的对应。在相应的经过中也许还可能会按request需求开展一些Server端的演算作为举个例子Rest-Api那样的劳动。不过对于大型的服务,情势相配格局就能够展示篇幅丰腴及情势僵化。Akka-http提供了一套routing DSL作为High-Level-Api的入眼组成都部队分。用routing DSL取代Low-Level-Api的情势相配方式能够更简明的编写制定HttpRequest到HttpResponse的转移服务,能越来越灵敏高效的完成今世大型Rest-Api服务。routing DSL达成Rest-Api服务的法子是经过营造多少个由组件Directives组合而成的三个多层南充治构造Route。Route是叁个类型:

  type Route = RequestContext ⇒ Future[RouteResult]

上面是个Route例子:

    val route: Flow[HttpRequest, HttpResponse, NotUsed]=
      get {
        pathSingleSlash {
          complete(HttpEntity(ContentTypes.`text/html(UTF-8)`,"<html><body>Hello world!</body></html>"))
        } ~
          path("ping") {
            complete("PONG!")
          } ~
          path("crash") {
            sys.error("BOOM!")
          }
      }

在下意气风发期商议的例证里大家得以如此使用route:

  val futBinding: Future[Http.ServerBinding] =
    connSource.to { Sink.foreach{ connection =>
      println(s"client address ${connection.remoteAddress}")
      //    connection handleWith flow
      //    connection handleWithSyncHandler syncHandler
      //connection handleWithAsyncHandler asyncHandler
      connection handleWith route
    }}.run()

Akka(30): Http:High-Level-Api,Routing DSL。handleWith(flow卡塔尔的参数应该是Flow[HttpRequest,HttpResponse,_]Akka(30): Http:High-Level-Api,Routing DSL。才对呀?这些大家先看看RouteResult对象: 

/**
 * The result of handling a request.
 *
 * As a user you typically don't create RouteResult instances directly.
 * Instead, use the methods on the [[RequestContext]] to achieve the desired effect.
 */
sealed trait RouteResult extends javadsl.server.RouteResult

object RouteResult {
  final case class Complete(response: HttpResponse) extends javadsl.server.Complete with RouteResult {
    override def getResponse = response
  }
  final case class Rejected(rejections: immutable.Seq[Rejection]) extends javadsl.server.Rejected with RouteResult {
    override def getRejections = rejections.map(r ⇒ r: javadsl.server.Rejection).toIterable.asJava
  }

  implicit def route2HandlerFlow(route: Route)(implicit
    routingSettings: RoutingSettings,
                                               parserSettings:   ParserSettings,
                                               materializer:     Materializer,
                                               routingLog:       RoutingLog,
                                               executionContext: ExecutionContext = null,
                                               rejectionHandler: RejectionHandler = RejectionHandler.default,
                                               exceptionHandler: ExceptionHandler = null): Flow[HttpRequest, HttpResponse, NotUsed] =
    Route.handlerFlow(route)
}

这里有个隐式转变route2HandlerFlow把Route调换到Flow[Akka(30): Http:High-Level-Api,Routing DSL。HttpRequest,HttpResponse,NotUsed],难题一蹴即至了。

从type Route=RequestContext => Future[RouteResult]Akka(30): Http:High-Level-Api,Routing DSL。可以看看:Route就是一个把RequestContext转变来Future[Akka(30): Http:High-Level-Api,Routing DSL。RouteResult]的函数。RequestContext实质上包裹了个Request以至对Request进行操作的景况、配置和工具:

/**
 * This class is not meant to be extended by user code.
 *
 * Immutable object encapsulating the context of an [[akka.http.scaladsl.model.HttpRequest]]
 * as it flows through a akka-http Route structure.
 */
@DoNotInherit
trait RequestContext {

  /** The request this context represents. Modelled as a `val` so as to enable an `import ctx.request._`. */
  val request: HttpRequest

  /** The unmatched path of this context. Modelled as a `val` so as to enable an `import ctx.unmatchedPath._`. */
  val unmatchedPath: Uri.Path

  /**
   * The default ExecutionContext to be used for scheduling asynchronous logic related to this request.
   */
  implicit def executionContext: ExecutionContextExecutor
...
}

Route是风流倜傥种可整合组件。我们能够用简短的Route组合成更加的多档案的次序的Route。下边是整合Route的两种方法:

1、Route转变:对输入的request,输出的response进行中间转播管理后把实际运算托付给下意气风发层内部(inner)Route

2、筛选Route:只恐怕切合某种条件的Route通过并谢绝任何不切合条件的Route

3、链接Route:假诺多个Route被拒绝,尝试下多少个Route。这几个是由此~ 操作符号完结的

在Akka-http的routing DSL里这个Route组合操作是通过Directive完成的。Akka-http提供了多量现存的Directive,大家也能够自定义一些非正规效果的Directive,详细的情况可以查询官方文书也许api文件。

Directive的表明方式如下:

dirname(arguments) { extractions =>
  ... // 内层inner route
}

上面是Directive的有些用例: 

上边包车型大巴三个route效果也正是:

val route: Route = { ctx =>
  if (ctx.request.method == HttpMethods.GET)
    ctx.complete("Received GET")
  else
    ctx.complete("Received something else")
}

val route =
  get {
    complete("Received GET")
  } ~
  complete("Received something else")

val route =
  get { ctx =>
    ctx.complete("Received GET")
  } ~
  complete("Received something else")

下边列出黄金时代部分Directive的组合例子:

val route: Route =
  path("order" / IntNumber) { id =>
    get {
      complete {
        "Received GET request for order " + id
      }
    } ~
    put {
      complete {
        "Received PUT request for order " + id
      }
    }
  }

def innerRoute(id: Int): Route =
  get {
    complete {
      "Received GET request for order " + id
    }
  } ~
  put {
    complete {
      "Received PUT request for order " + id
    }
  }
val route: Route = path("order" / IntNumber) { id => innerRoute(id) }

val route =
  path("order" / IntNumber) { id =>
    (get | put) { ctx =>
      ctx.complete(s"Received ${ctx.request.method.name} request for order $id")
    }
  }

val route =
  path("order" / IntNumber) { id =>
    (get | put) {
      extractMethod { m =>
        complete(s"Received ${m.name} request for order $id")
      }
    }
  }

val getOrPut = get | put
val route =
  path("order" / IntNumber) { id =>
    getOrPut {
      extractMethod { m =>
        complete(s"Received ${m.name} request for order $id")
      }
    }
  }

val route =
  (path("order" / IntNumber) & getOrPut & extractMethod) { (id, m) =>
    complete(s"Received ${m.name} request for order $id")
  }

val orderGetOrPutWithMethod =
  path("order" / IntNumber) & (get | put) & extractMethod
val route =
  orderGetOrPutWithMethod { (id, m) =>
    complete(s"Received ${m.name} request for order $id")
  }

地方例子里的~ & | 定义如下:

object RouteConcatenation extends RouteConcatenation {

  class RouteWithConcatenation(route: Route) {
    /**
     * Returns a Route that chains two Routes. If the first Route rejects the request the second route is given a
     * chance to act upon the request.
     */
    def ~(other: Route): Route = { ctx ⇒
      import ctx.executionContext
      route(ctx).fast.flatMap {
        case x: RouteResult.Complete ⇒ FastFuture.successful(x)
        case RouteResult.Rejected(outerRejections) ⇒
          other(ctx).fast.map {
            case x: RouteResult.Complete               ⇒ x
            case RouteResult.Rejected(innerRejections) ⇒ RouteResult.Rejected(outerRejections ++ innerRejections)
          }
      }
    }
  }
}

  /**
   * Joins two directives into one which runs the second directive if the first one rejects.
   */
  def |[R >: L](that: Directive[R]): Directive[R] =
    recover(rejections ⇒ directives.BasicDirectives.mapRejections(rejections ++ _) & that)(that.ev)

  /**
   * Joins two directives into one which extracts the concatenation of its base directive extractions.
   * NOTE: Extraction joining is an O(N) operation with N being the number of extractions on the right-side.
   */
  def &(magnet: ConjunctionMagnet[L]): magnet.Out = magnet(this)

咱们得以从地点那一个示范例子得出结论:Directive的结合技术是routing DSL的大旨。来探视Directive的组合才具是怎么促成的。Directive类定义如下:

//#basic
abstract class Directive[L](implicit val ev: Tuple[L]) {

  /**
   * Calls the inner route with a tuple of extracted values of type `L`.
   *
   * `tapply` is short for "tuple-apply". Usually, you will use the regular `apply` method instead,
   * which is added by an implicit conversion (see `Directive.addDirectiveApply`).
   */
  def tapply(f: L ⇒ Route): Route
  ...
}
  /**
   * Constructs a directive from a function literal.
   */
  def apply[T: Tuple](f: (T ⇒ Route) ⇒ Route): Directive[T] =
    new Directive[T] { def tapply(inner: T ⇒ Route) = f(inner) }

  /**
   * A Directive that always passes the request on to its inner route (i.e. does nothing).
   */
  val Empty: Directive0 = Directive(_(()))
...
  implicit class SingleValueModifiers[T](underlying: Directive1[T]) extends AnyRef {
    def map[R](f: T ⇒ R)(implicit tupler: Tupler[R]): Directive[tupler.Out] =
      underlying.tmap { case Tuple1(value) ⇒ f(value) }

    def flatMap[R: Tuple](f: T ⇒ Directive[R]): Directive[R] =
      underlying.tflatMap { case Tuple1(value) ⇒ f(value) }

    def require(predicate: T ⇒ Boolean, rejections: Rejection*): Directive0 =
      underlying.filter(predicate, rejections: _*).tflatMap(_ ⇒ Empty)

    def filter(predicate: T ⇒ Boolean, rejections: Rejection*): Directive1[T] =
      underlying.tfilter({ case Tuple1(value) ⇒ predicate(value) }, rejections: _*)
  }
}

注意implicit ev: Tuple[L]是给compiler的证例,它要求Tuple[L]留存于可视域。Akka-http提供了独具二十四个TupleXX[L]的隐形实例。再理会implicit class singleValueModifiers[T]:它提供了多层Directive的机动展平,可以完结上面包车型客车电动转变结果:

Directive1[T] = Directive[Tuple1[T]]
Directive1[Tuple2[M,N]] = Directive[Tuple1[Tuple2[M,N]]] = Directive[Tuple2[M,N]]
Directive1[Tuple3[M,N,G]] = ... = Directive[Tuple3[M,N,G]]
Directive1[Tuple4[M1,M2,M3,M4]] = ... = Directive[Tuple4[M1,M2,M3,M4]]
...
Directive1[Unit] = Directive0

Directive1,Directive0:

  type Directive0 = Directive[Unit]
  type Directive1[T] = Directive[Tuple1[T]]

下边是那二种Directive的运用形式:

 

  dirname { route }                  //Directive0
  dirname[L] { L => route }          //Directive1[L]
  dirname[T] { (T1,T2...) => route}  //Directive[T]

 

其余类型值到Tuple的自动转变是经过Tupler类达成的:

/**
 * Provides a way to convert a value into an Tuple.
 * If the value is already a Tuple then it is returned unchanged, otherwise it's wrapped in a Tuple1 instance.
 */
trait Tupler[T] {
  type Out
  def OutIsTuple: Tuple[Out]
  def apply(value: T): Out
}

object Tupler extends LowerPriorityTupler {
  implicit def forTuple[T: Tuple]: Tupler[T] { type Out = T } =
    new Tupler[T] {
      type Out = T
      def OutIsTuple = implicitly[Tuple[Out]]
      def apply(value: T) = value
    }
}

private[server] abstract class LowerPriorityTupler {
  implicit def forAnyRef[T]: Tupler[T] { type Out = Tuple1[T] } =
    new Tupler[T] {
      type Out = Tuple1[T]
      def OutIsTuple = implicitly[Tuple[Out]]
      def apply(value: T) = Tuple1(value)
    }
}

自己的明白是:Route里Directive的主要性功用能够分成两有的:一是如程序菜单拣选,二是对Request,Response,Entity的读写。大家把第二项成效放在未来的商酌里,下面就提供部分RestApi的菜单拣选样例:

trait UsersApi extends JsonMappings{
  val usersApi =
    (path("users") & get ) {
       complete (UsersDao.findAll.map(_.toJson))
    }~
    (path("users"/IntNumber) & get) { id =>
        complete (UsersDao.findById(id).map(_.toJson))
    }~
    (path("users") & post) { entity(as[User]) { user =>
        complete (UsersDao.create(user).map(_.toJson))
      }
    }~
    (path("users"/IntNumber) & put) { id => entity(as[User]) { user =>
        complete (UsersDao.update(user, id).map(_.toJson))
      }
    }~
    (path("users"/IntNumber) & delete) { userId =>
      complete (UsersDao.delete(userId).map(_.toJson))
    }
}

trait CommentsApi extends JsonMappings{
  val commentsApi =
    (path("users"/IntNumber/"posts"/IntNumber/"comments") & get ) {(userId, postId) =>
       complete (CommentsDao.findAll(userId, postId).map(_.toJson))
    }~
      (path("users"/IntNumber/"posts"/IntNumber/"comments"/IntNumber) & get) { (userId, postId, commentId) =>
        complete (CommentsDao.findById(userId, postId, commentId).map(_.toJson))
    }~
      (path("comments") & post) { entity(as[Comment]) { comment =>
        complete (CommentsDao.create(comment).map(_.toJson))
      }
    }~
      (path("users"/IntNumber/"posts"/IntNumber/"comments"/IntNumber) & put) { (userId, postId, commentId) => entity(as[Comment]) { comment =>
        complete (CommentsDao.update(comment, commentId).map(_.toJson))
      }
    }~
      (path("comments"/IntNumber) & delete) { commentId =>
        complete (CommentsDao.delete(commentId).map(_.toJson))
    }
}

trait PostsApi extends JsonMappings{
  val postsApi =
    (path("users"/IntNumber/"posts") & get){ userId =>
      complete (PostsDao.findUserPosts(userId).map(_.toJson))
    }~
    (path("users"/IntNumber/"posts"/IntNumber) & get) { (userId,postId) =>
      complete (PostsDao.findByUserIdAndId(userId, postId).map(_.toJson))
    }~
    (path("users"/IntNumber/"posts") & post) { userId => entity(as[Post]) { post =>
      complete (PostsDao.create(post).map(_.toJson))
    }}~
    (path("users"/IntNumber/"posts"/IntNumber) & put) { (userId, id) => entity(as[Post]) { post =>
      complete (PostsDao.update(post, id).map(_.toJson))
    }}~
    (path("users"/IntNumber/"posts"/IntNumber) & delete) { (userId, postId) =>
      complete (PostsDao.delete(postId).map(_.toJson))
    }
}

  val routes =
    pathPrefix("v1") {
      usersApi ~
      postsApi ~
      commentsApi
    } ~ path("")(getFromResource("public/index.html"))

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

本文由永利棋牌官方下载发布于永利棋牌官方下载,转载请注明出处:Akka(30): Http:High-Level-Api,Routing DSL

您可能还会对下面的文章感兴趣: