Spray.io搭建Rest服务

Spray.io尝试

  • 使用Spray.io搭建Rest服务
  • Spray.io搭建Rest — 支持Twirl模板并部署
  • Spray.io搭建Rest — 支持WebSocket

使用Spray.io搭建Rest服务

Spray 是一个开源的 REST/HTTP 工具包和底层网络 IO 包,基于 Scala 和 Akka 构建。轻量级、异步、非堵塞、基于 actor 模式、模块化和可测试是 spray 的特点。

你可以通过git@osc上面获取代码 http://git.oschina.net/for-1988/Simples/tree/master/SpraySimple 

工程环境

  • IDE: IntelliJ IDEA 13.1.1 (安装Scala、SBT插件)
  • Spray 1.2, akka 2.2.3 , Scala 2.10.3

SBT配置

build.sbt

name := "SpraySimple"
version := "1.0"
scalaVersion  := "2.10.3"
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8")

resolvers ++= Seq(
  "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/",
  "Spray repository" at "http://repo.spray.io/"
)

libraryDependencies ++= {
  val akkaV = "2.2.3"
  val sprayV = "1.2.0"
  Seq(
    //"org.java-websocket"  %   "Java-WebSocket" % "1.3.1",
    "org.json4s"    %% "json4s-native"   % "3.2.4",
    "io.spray"            %%  "spray-json"     % "1.2.5",
    "io.spray"            %   "spray-can"      % sprayV,
    "io.spray"            %   "spray-routing"  % sprayV,
    "com.typesafe.akka"   %%  "akka-actor"     % akkaV,
    "com.typesafe.akka"   %%  "akka-testkit"   % akkaV   % "test",
    "io.spray"            %   "spray-testkit"  % sprayV  % "test",
    "org.scalatest"       %%  "scalatest"      % "2.0"   % "test",
    "junit"               %   "junit"          % "4.11"  % "test",
    "org.specs2"          %%  "specs2"         % "2.2.3" % "test"
  )
}

plugins.sbt

logLevel := Level.Warn

addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.1")
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.2")
Spray.io搭建Rest服务_第1张图片


Spray 启动web服务

    Spray的Spray-Can模块来提供web服务,它本身就提供了服务器功能,这样就无需其他服务器。启动Http监听只需要下面一句代码

IO(Http) ! Http.Bind(httpServer, Configuration.host, port = Configuration.portHttp)

    直接借助Scala的main方法就可以启动。Spray是基于Akka构建的,所以启动需要基于Akka的ActorSystem。httpServer对象就是一个Akka的Actor。

    完整的启动类:

object Server extends App with Routes {
  implicit lazy val system = ActorSystem("server-system")
  lazy val index = system.actorOf(Props[IndexActor], "index")

  implicit lazy val routes = {
    new IndexService(index)(system).route
  }

  IO(Http) ! Http.Bind(httpServer, Configuration.host, port = Configuration.portHttp)
}

object Configuration {

  import com.typesafe.config.ConfigFactory

  private val config = ConfigFactory.load
  config.checkValid(ConfigFactory.defaultReference)

  val host = config.getString("http.server.host")
  val portHttp = config.getInt("http.server.ports.http")
  val portTcp = config.getInt("http.server.ports.tcp")
  val portWs = config.getInt("http.server.ports.ws")
}

Spray的路由

    Spray的spray-routing模块提供路由功能,上面可以看到启动类Server继承了Routes,这个Trait是我们自己写来处理路由部分的代码,我们先看下它的实现代码

trait Routes extends RouteConcatenation with StaticRoute with AbstractAkkaSystem {

  val httpServer = system.actorOf(Props(classOf[HttpServer], allRoutes))

  implicit def routes: Route


  lazy val allRoutes = logRequest(showReq _) {
    routes ~ staticRoute
  }

  private def showReq(req: HttpRequest) = LogEntry(req.uri, InfoLevel)
}


trait StaticRoute extends Directives {
  this: AbstractAkkaSystem =>

  lazy val staticRoute =
    path("favicon.ico") {
      getFromResource("favicon.ico")
    } ~
      pathPrefix("markers") {
        getFromResourceDirectory("markers/")
      } ~
      pathPrefix("css") {
        getFromResourceDirectory("css/")
      } ~
      pathEndOrSingleSlash {
        getFromResource("index.html")
      } ~ complete(NotFound)
}

AbstractAkkaSystem:

trait AbstractAkkaSystem {
  implicit def system: ActorSystem
}


这里我们初始化了HttpServer对象,并定义了隐式参数routes,还有对静态资源的路由配置。在Server中,我们对routes进行了实现,加入了IndexService的实现类。在这个类中,我们实现了一个很简单的Rest功能。

HttpServer对象

class HttpServer(route: Route)  extends Actor with HttpService with ActorLogging {

  implicit def actorRefFactory = context

  override def receive = runRoute(route)
}
HttpServer对象实现了spray.routing.HttpService 和akka.actor.Actor,
implicit def actorRefFactory = context    //实现HttpService中的隐式方法 actorRefFactory 


override def receive = runRoute(route)   // 实现Actor的receive方法,交给HttpService中的runRoute处理

路由映射及返回资源处理

class IndexActor extends Actor with ActorLogging {
  override def receive = {
    case None =>
  }
}

class IndexService(index: ActorRef)(implicit system: ActorSystem) extends Directives with Json4sSupport {
  implicit def json4sFormats: Formats = DefaultFormats

  lazy val route =
    pathPrefix("page") {
      val dir = "page/"
      pathEndOrSingleSlash {
        getFromResource(dir + "index.html")
      } ~
        getFromResourceDirectory(dir)
    } ~
      path("echo" / Segment) {
        message => get {
          complete {
            s"${message}"
          }
        }
      } ~
      path("person") {
        get {
          complete {
            val person = new Person("Feng Jiang", 26)
            person
          }
        }
      }
}



这里添加了三个路由映射,1.打开index.html,2.回显 ~/echo/{message}  , 3.返回Person对象的json

Spray.io搭建Rest服务_第2张图片


你可能感兴趣的:(scala,akka,Spray.io)