Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2011-11-07) lift.ebb 1.ViewAllCategories的总结与问题

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

Ebb的第一个use case,是view all categories,即查看所有的论坛组。先看看usebb的首页是什么样的:

image

再看我现在做成的样子:

image

虽然样子有点丑,但是好歹数据已经从数据库里取出来了。最关键的是,对lift的恐惧感大大减小,隐约开始理解它的运行方式了。

这是在教主的领导之下,使用他的rup开发方式,实现的第一个use case。我本打算先看几天的lift,差不多熟悉了再动手,但是教主说,让我直接在他的ebb代码基础上做,先照葫芦画瓢,做出功能后,再想着改进和学习。


总结:

一、现在的liftweb (lift2.4m4) 只支持到2.9.0.1(以及2.8.1),不支持最新的2.9.1。这个项目,使用的是2.8.1

二、liftweb使用的还是sbt 0.7.x,而不是最新的0.10.x。这个项目,使用的是0.7.5

三、配合jrebel,可以将修改代码生效的时间由10秒左右,减小到4秒。

四、如何在lift中使用jrebel,将另写一篇文章

关于lift的理解

我用过很多mvc类框架及wicket/tapestry这样的非mvc,但初看lift代码时,还是觉得摸不着头。因为在lift的代码中,有很多奇怪的符号及独特的渲染方式:类似jquery的css selector替换。

lift里面东西很多,这次只接触到snippet,所以只总结这一点。

在mvc中,请求一个页面的流程是这样的:一个请求到来后,首先被router获取。它根据一定的规则,将它转发给某个controller中的某个方法(action)。在action中,可以取得request中的参数,然后根据需求,调用其它的类或方法,得到所需数据,传给view。view使用这些数据,渲染出最终的html,发给浏览器。可以看到,在这里controller是老大,它负责取数据,丢给view小弟处理。

在lift中,是反过来的。当请求到来后,首先找到的是view。比如我请求http://localhost/abc.html,它会首先在webapp下找到abc.html这个文件。abc.html是一个正常且完整的html,不同之处在于,它里面有一些html标签,及奇怪的class属性(见后面的例子)。这些class实际上是一些声明,告诉lift如何处理、替换或填充这部分模板。lift将调用对应的snippet类(也可以看作是Component),改变模板内容,变成最终的html。可见这里,view是老大,它根据自己的模板内容,召唤snippet小弟过来给自己化妆打扮。所以lift这种方式,叫做View-first。

见这个html页面index.html

lift:surround?with=default;at=content**">

bbs

lift:ForumSnippet.forumlist** maintable">
» {cat_name}
{l_Forum} {l_Topics} {l_Posts} {l_LatestPost}
{forum_status}
{forum_name}
{forum_descr}
{total_topics}
{total_posts}
{latest_post}
On: {on_date}

首先直接用浏览器打开这个文件,看是什么样子:

image

可见的确是一个很像“模板”的html页面。为什么经过lift渲染之后,会变成这样呢?

image

关键就在于代码中那两处红色的class。

1、lift:surround?with=default;at=content

这句话是告诉lift,先找到templates-hidden/default.html这个布局文件,然后用index.html的内容,替换default.html中的content**” />。

templates-hidden/default.html内容如下:


<meta http-equiv="content-type" content="text/html; charset=UTF-8" />      
<meta name="description" content="" />      
<meta name="keywords" content="" />      
<title>kkkk</title>      
<script id="jquery" src="/classpath/jquery.js" type="text/javascript"/>      


**<font color="#ff0000"><lift:bind name="content" />         

**

查看index.html最终生成的html源代码,里面的确用到了default.html中的代码:

image

2、lift:ForumSnippet.forumlist

这句话告诉lift,使用code.snippet.ForumSnippet.forumlist()方法来处理其所在的table标签(及内部标签)。ForumSnippet是什么样子呢?见下面代码:

object ForumSnippet {
def forumlist: CssSel =

"*****" **<font color="#800080">#></font>** (for (cat <- cats) yield {      
  "**<font color="#ff8040">.t-cat_header</font>**" #> ("@cat_name" #> cat.name) &      
  "**<font color="#ff8000">.t-forum</font>**" #> ( for {      
      f <- cat.forums      
      lastTopic <- topics.lookup(f.last_topic_id)      
  } yield {      

    val lastPost = posts.lookup(lastTopic.last_post_id).get      
    val lastPoster = members.lookup(lastPost.poster_id).get      
    val lastTopicTitle = (if(lastTopic.count_replies>1) "Re: " else "") + lastTopic.topic_title 

    "**<font color="#ff8000">.forumname *</font>**" #> f.name &      

    ".forumdescr *" #> f.descr &     
    ".total_topics" #> f.topics &      
    ".total_posts" #> f.posts &      
    ".latest_post *" #> ("@latest_post" #> lastTopicTitle) &      
    ".by_author *" #> ("@by_author" #> {lastPoster.name}) &      
    ".on_date *" #> ("@on_date" #> new SimpleDateFormat().format(lastPost.post_time)) 

  })     
})      

}

这段代码中,有很多奇怪的符号。但如果你使用过jquery的话,可能就会猜到:它首先将html模板(即

xxx
这一段)解析为一个xml树,然后使用css selector定位到对应的节点,最后使用实际数据去替换内容。

首先需要了解的是紫色的#>符号,它在代码中大量使用,意思是replacedWith,即用后面的数据替换左边对应的节点内容。

例如:

“.forumdescr *” #> f.descr

左边是css selector,“.forumdescr"表示class=“.forumdescr"节点,“.forumdescr .aaa"表示”.forumdesc"下的所有”.aaa"节点,“.forumdescr *“表示”.forumdescr"下的所有节点。

这句代码表示将”.forumdescr"下的所有内容替换为f.descr。

每行最后的&,表示将多个操作连接起来。

如何替换属性?

“.forumname [href]” #> http://google.com

comments powered by Disqus