zoukankan      html  css  js  c++  java
  • Xitrum学习笔记03

    Action:

    Xitrum 提供了3种Action:普通Action, FutureAction 和 ActorAction

    它们都是Trait,而不是 Class

    1. 普通Action:

    当请求到来时,Action实现类直接在Netty的 IO线程上运行,不能用普通Action来执行 消耗很长时间的处理,否则Netty就不能接收新的连接或发出响应到客户端

    import xitrum.Action
    import xitrum.annotation.GET
    @GET("hello")
    class HelloAction extends Action {
      def execute() {
        respondText("Hello")
      }
    }

    2. FutureAction:

    扩展了 Action,FutureAction实现类异步运行在和ActorAction相同的线程池上,这个线程池和Netty线程池是分离的

    FutureAction实现类的执行context是 xitrum.Config.actorSystem.dispatcher.

    trait FutureAction extends Action

    import xitrum.FutureAction
    import xitrum.annotation.GET
    @GET("hello")
    class HelloAction extends FutureAction {
      def execute() {
        respondText("hi")
      }
    }

    3. ActorAction:

    trait ActorAction extends Actor with Action

    实现类是一个 Akka actor。

    当有需求时,一个actor实例被创建。当连接关闭时,或者响应通过 respondText/respondView 等方法被发出时,actor会被停止。

    对于分块的响应,actor会在最后一个块儿的响应发出后才被停止。

    actor运行在命名为"xiturm"的Akka actor系统的线程池中。

     1 import scala.concurrent.duration._
     2 import xitrum.ActorAction
     3 import xitrum.annotation.GET
     4 @GET("actor")
     5 class HelloAction extends ActorAction {
     6   def execute() {
     7     // See Akka doc about scheduler 9     context.system.scheduler.scheduleOnce(3.seconds, self, System.currentTimeMillis())
    10     // See Akka doc about "become"
    11     context.become {
    12       case pastTime =>
    13       respondInlineView(s"It's $pastTime Unix ms 3s ago.")
    14     }
    15   }
    16 }

    响应(Response)方式:

    1.  对于action来说,要向客户端发出响应,可以调用如下方法

    • respondView: responds view template file, with or without layout
    • respondInlineView: responds embedded template (not separate template file), with or without layout
    • respondText("hello"): responds a string without layout
    • respondHtml("<html>...</html>"): same as above, with content type set to “text/html”
    • respondJson(List(1, 2, 3)): converts Scala object to JSON object then responds
    • respondJs("myFunction([1, 2, 3])")
    • respondJsonP(List(1, 2, 3), "myFunction"): combination of the above two
    • respondJsonText("[1, 2, 3]")
    • respondJsonPText("[1, 2, 3]", "myFunction")
    • respondBinary: responds an array of bytes
    • respondFile: sends a file directly from disk, very fast because zero-copy (aka send-file) is used
    • respondEventSource("data", "event")

    2. 响应返回事先创建好的View模板文件内容

    要运用这种方式,每个Action scala文件都要对应一个View jade文件。代码示例如下:

    scr/main/scala/mypackage/MyAction.scala:

    package mypackage
    import xitrum.Action
    import xitrum.annotation.GET
    @GET("myAction")
    class MyAction extends Action {
      def execute() {
        respondView()
      }
      def hello(what: String) = "Hello %s".format(what)
    }

    scr/main/scalate/mypackage/MyAction.jade:

    - import mypackage.MyAction
    !!! 5
    html
      head
        != antiCsrfMeta
        != xitrumCss  //包含了Xitrum默认的CSS。这个CSS是可以移除的
        != jsDefaults //包含了 jQuery、jQuery验证插件等等内容,要放在<head>标签中
        title Welcome to Xitrum
      body
        a(href={url}) Path to the current action
        p= currentAction.asInstanceOf[MyAction].hello("World") //将currentAction转换为MyAction,并调用其hello方法
        != jsForView  //包含了由jsAddToView标签添加的JavaScript代码,jsForView标签应该放在整个layout的底部

    在View模板中,可以使用 xitrum.Action中定义的所有方法,而且也可以使用由Scalate提供的一些utility方法(参考 Scalate doc)

    默认的 Scalate 模板类型是 Jade,其他的有 Mustache, Scaml 和 Ssp。在config/xitrum.conf文件中配置默认模板类型.

      # Comment out if you don't use template engine.
      template {
        "xitrum.view.Scalate" {
          defaultType = jade  # jade, mustache, scaml, or ssp
        }
      }

    也可以在Action实现类调用 respondView时指定模板类型

    val options = Map("type" ->"mustache")
    respondView(options)

    如果需要在View中多次调用Action实现类的的方法的话,只需要将currentAction做一次转换,如:

    - val myAction = currentAction.asInstanceOf[MyAction]; import myAction._
    p= hello("World")
    p= hello("Scala")
    p= hello("Xitrum")

    Layout

    利用respondView或respondInlineView提交一个View时,Xitrum会把View内容表示成一个String,然后把这个String设置给renderedView变量。

    Xitrum调用当前Action的layout方法,把方法的结果返回给浏览器。如果当前Action的layout方法没被调用,则没有结果返回给浏览器。

    默认的layout方法只返回 renderedView 本身,可以通过重写layout方法以添加关于view的其他内容。如果重写的layout方法中包含renderedView,它只是作为layout的一部分内容。

    layout方法在action的view生成之后才被调用,layout方法返回的内容就是要响应到浏览器中的内容。

    可以通过创建一个继承自Action的Trait,并将其相应的View模板文件定义为通用layout。再让其他Action scala实现这个Trait,这样其他Action的页面就会包含这个通用的layout。

    示例:

    src/main/scala/mypackage/AppAction.scala

    package mypackage
    import xitrum.Action
    trait AppAction extends Action {
      override def layout = renderViewNoLayout[AppAction]() //将AppAction.jade中的内容作为页面内容的模板
    }

    src/main/scalate/mypackage/AppAction.jade

    !!! 5
    html
      head
        != antiCsrfMeta
        != xitrumCss
        != jsDefaults
        title Welcome to Xitrum
      body
        != renderedView  -#如果没有这一句,使用这个模板的其他View的内容不会呈现
        != jsForView

    src/main/scala/mypackage/MyAction.scala

    package mypackage
    import xitrum.annotation.GET
    @GET("myAction")
    class MyAction extends AppAction {
      def execute() {
        respondView()
      }
      def hello(what: String) = "Hello %s".format(what)
    }

    scr/main/scalate/mypackage/MyAction.jade:

    - import mypackage.MyAction
    a(href={url}) Path to the current action
    p= currentAction.asInstanceOf[MyAction].hello("World")

    此示例验证成功,AppAction.jade中的body需要含有!=renderedView

    layout不在View模板里的示例(直接写到 Action Scala文件里)

    示例1:

    import xitrum.Action
    import xitrum.view.DocType
    trait AppAction extends Action {
      override def layout = DocType.html5(
        <html>
          <head>
             {antiCsrfMeta}
             {xitrumCss}
             {jsDefaults}
             <title>Welcome to Xitrum</title>
           </head>
           <body>
             {renderedView}
             {jsForView}
           </body>
        </html>
      )
    }

    示例2:

    val specialLayout = () =>
       DocType.html5(
         <html>
           <head>
              {antiCsrfMeta}
              {xitrumCss}
              {jsDefaults}
              <title>Welcome to Xitrum</title>
            </head>
            <body>
              {renderedView}
              {jsForView}
            </body>
          </html>
       )
    respondView(specialLayout _)

    Inline view

    import xitrum.Action
    import xitrum.annotation.GET

      @GET("myAction")
      class MyAction extends Action {
        def execute() {
          val s = "World" // Will be automatically HTML-escaped
          respondInlineView(
             <p>Hello <em>{s}</em>!</p>
          )
        }
      }

    Render fragment 

    有两个Jade View文件:

    scr/main/scalate/mypackage/MyAction.jade,scr/main/scalate/mypackage/_MyFragment.jade

    如果想提交fragment文件到相同路径下的其他Jade文件里,可以使用

    renderFragment[MyAction]("MyFragment")

    如果在这种情况下,MyAction是当前action,则上面的代码可以写成 renderFragment("MyFragment")

    返回其他action的View

    使用respondView[ClassName]()和redirectTo[ClassName]()

    示例:

    package mypackage
    import xitrum.Action
    import xitrum.annotation.{GET, POST}
    @GET("login")
    class LoginFormAction extends Action {
      def execute() {
        // Respond scr/main/scalate/mypackage/LoginFormAction.jade
        respondView()
      }
    }
    @POST("login")
    class DoLoginAction extends Action {
      def execute() {
        val authenticated = ...
        if (authenticated)
          redirectTo[HomeAction]()  // 定向到HomeAction的View
        else
           // Reuse the view of LoginFormAction
           respondView[LoginFormAction]()  //定向到LoginForAction的View
        }
    }

    redirectTo和respondView的区别:

    redirectTo:不需要定向到的Action提供相应的模板;默认HttpResponseStatus是302

    respondView:需要定向到的Action提供相应的模板;HttpResponseStatus是200

    也可以从一个Action,定向到多个View

    package mypackage
    import xitrum.Action
    import xitrum.annotation.GET
    // These are non-routed actions, for mapping to view template files:
    // scr/main/scalate/mypackage/HomeAction_NormalUser.jade
    // scr/main/scalate/mypackage/HomeAction_Moderator.jade
    // scr/main/scalate/mypackage/HomeAction_Admin.jade
    trait HomeAction_NormalUser extends Action
    trait HomeAction_Moderator extends Action
    trait HomeAction_Admin extends Action
    @GET("")
    class HomeAction extends Action {
      def execute() {
        val userType = ...
        userType match {
          case NormalUser => respondView[HomeAction_NormalUser]() 
          case Moderator => respondView[HomeAction_Moderator]()
          case Admin => respondView[HomeAction_Admin]()
        }
      }
    }

    使用respondView[HomeAction_NormalUser]()这样的写法是 类型安全的 写法,也可以使用String参数把scalate的View的位置传给respondView方法

    respondView("mypackage/HomeAction_NormalUser")
    respondView("mypackage/HomeAction_Moderator")
    respondView("mypackage/HomeAction_Admin")

    Component

    Component是在各个View中复用的组件,和Action有些类似

    • Component没有routes(@GET("")括号中的内容就是route),因此不需要使用execute方法
    • 因为Component只是提交一个View的片段(fragment),而不是发出整个的响应内容,所以在Component要调用renderXXX来代替respondXXX
    • 一个Component可以没有、有一个 或 有多个关联的View模板

    示例:

    package mypackage
    import xitrum.{FutureAction, Component}
    import xitrum.annotation.GET
    class CompoWithView extends Component {
      def render() = {
        // Render associated view template, e.g. CompoWithView.jade
        // Note that this is renderView, not respondView!
        renderView()
      }
    }
    
    class CompoWithoutView extends Component {
       def render() = {
         "Hello World"
       }
    }
    
    @GET("foo/bar")
    class MyAction extends FutureAction {
       def execute() {
         respondView()
      }
    }

    MyAction.jade:

    - import mypackage._
    != newComponent[CompoWithView]().render()
    != newComponent[CompoWithoutView]().render()
  • 相关阅读:
    常用知识点集合
    LeetCode 66 Plus One
    LeetCode 88 Merge Sorted Array
    LeetCode 27 Remove Element
    LeetCode 26 Remove Duplicates from Sorted Array
    LeetCode 448 Find All Numbers Disappeared in an Array
    LeetCode 219 Contains Duplicate II
    LeetCode 118 Pascal's Triangle
    LeetCode 119 Pascal's Triangle II
    LeetCode 1 Two Sum
  • 原文地址:https://www.cnblogs.com/sunspeedzy/p/6841353.html
Copyright © 2011-2022 走看看