`
laowang
  • 浏览: 38079 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

hellolift学习笔记(7)

阅读更多
学习笔记中断了将近一个月,除了事儿多、工作忙之外,学习的过程也确实让我头疼,因为这次涉及到了lift框架核心的一些东西,LifteSession,LiftServlet等等,我不得不经常停下来再啃几章《Programming In Scala》。过程中着实感触不少:1.没有ide的调试支持,只靠println大法来学习框架,实在太痛苦;2.不好好锻炼一下函数式编程的思维,学习scala/lift实在不是太容易的事情,现在看从java开发者转变到scala的开发者也许没有想象中的容易;3.scala的很多特性也许让写代码变得简单,但是给阅读代码带来的复杂程度也不小;4.满屏幕Type Parameterization 的东西实在让人看着头大。

闲话说了不少了,赶紧把刚刚理清楚的思路记下来。

8.Create An Entry(1)--toForm

创建一个Entry的过程可以分以下三个过程来理解:定义Entry类,根据类的定义创建Form表单,获取表单提交的信息,写入数据库。我们还是按照看到的顺序来学习设计到的东西。
entry.html->entry()
def entry = (new Entry).author(User.currentUser).toForm(Full("Post"),
				 (t: Entry) => {
				   t.save
           println("after entry.save")
				  S.redirectTo("/view?id=" + t.id)
         })

首先是author的赋值,这是一个链式调用,赋值返回的结果还是一个entry,我们来看author 的定义。
object author extends MappedLongForeignKey(this, User) {
    override def dbDisplay_? = false
  }

author 是一个object 而不是一个简单的val,因为我们需要通过重载他所继承的基类的方法来对author的行为(包括约束,展现等)进行定制。

MappedLongForeignKey是MappedField的子类,在MetaMapper的findMagicFields方法实现中我们能看到,lift是通过查找是MappedField实例的属性来确定需要由Mapper框架维护的属性的。
abstract class MappedLongForeignKey[T<:Mapper[T],O<:KeyedMapper[Long, O]](theOwner: T, foreign: => KeyedMetaMapper[Long, O])
extends MappedLong[T](theOwner)  with MappedForeignKey[Long,T,O] with BaseForeignKey

abstract class MappedLong[T<:Mapper[T]](val fieldOwner: T) extends MappedField[Long, T] 

查看MeppedField的子类,能得到可以用的类型
MappedEnumList, MappedFakeClob, MappedForeignKey, MappedDateTime, MappedText, MappedPassword, MappedDouble, MappedBoolean, MappedBinary, MappedInt, MappedEnum, MappedLong, MappedString

MappedForeignKey相关的内容对现在的过程没有影响,我们以后再来研究。

在MappedField的apply方法中可以看到,在函数的最后会返回fieldOwner,这个fieldOwner就是Entry对象,是通过 extends时的this传入的,这有助于我们理解,为什么每一个属性的定义都要加上个this.
  def apply[Q <% FieldType](v: Q): OwnerType = {
    this.set(v)
    fieldOwner
  }


之后是一个toForm的调用
def toForm(button : Box[String], f : (A) => Any) 
Present the model as a form and execute the function on submission of the form 
param
f - - the function to execute on form submission 
button - - If it's Full, put a submit button on the form with the value of the parameter
return
- the form

看他的执行过程之前先来看看这两个参数。button简单,就是显示在submit按钮上的值。f参数就有点神奇了,因为toForm的执行和f的执行之间可隔着两个http的过程呢,还有用户的参与。搞明白这点的过程相当曲折,说白了却也比较简单:在toForm的执行过程中,lift会通过S对象把f保存在一个ThreadGlobal(java中ThreadLocal封装)的变量中,并且把保存的key值通过一个hidden域输出到表单中;当表单提交时,在LiftSession.runParams 方法中会把这个方法取出来执行。具体实现的过程实在是比较复杂,好在我们暂时还不需要彻底搞明白。
(注:其实不止是submit如此,每一个字段都会有这样一个方法保存,通过生成input的name属性来保存关联,估计lift里,这个name属性是不能再被利用了)
这里有还有一点值得说明的是,这个toForm生成的表单的提交地址,就是表单的访问地址。但是这个提交请求在常规的render执行之前先执行了这里的f方法,然后被 S.redirectTo(...)重定向,中止了正常的处理过程。如果去掉 S.redirectTo()的调用,将在数据保存后,看到一个新的空白的表单。

现在可以放下包袱来看Form的输出过程了。
1).Mapper.toForm方法首先通过getSingleton的调用获得到他的伴生对象
2).调用定义在伴生对象的基类KeyedMetaMapper中的toForm方法,逐个生成属性字段需要的表单项
2.1) 依次调用被映射的属性对象,根据属性对象自身的各种属性决定是否调用属性对象的toForm方法,生成表单项(各种input)
2.2) 获取MappedField的displayName 通过formatFormLine方法输出显示名,并加上各种格式代码
3).Mapper.toForm保存onSubmit函数(f),生成submit按钮

我们来看这个过程中几个需要关注的东西
1) 我们必须在class中重载一个getSingleton方法,以找到伴生对象
2) 在属性对象(MappedField)中的一些值可以用来控制表单的显示,比如说author属性中的 dbDisplay_? 如果设为false,则不会显示在表单中
3) 可以通过重载displayName来控制字段的显示名称
4) MappedField的toForm方法会调用_toForm方法来最终决定输出内容,如果想自己控制输出格式,可以考虑重载这个方法,比如说
 object title extends MappedString(this, 128) {
    override def displayName = "标题"

    override def _toForm: Box[Elem] =
      fmapFunc({s: List[String] => this.setFromAny(s)}) {
        name =>
                Full(<div> <input type='text' id={fieldId} maxlength={maxLen.toString}
                name={name}
                value={is match {case null => "" case s => s.toString}}/>元素级别加点啥呢?</div>)
      }
  }

5) 如果想在行一级修改缺省输出,可以重新定义KeyedMetaMapper的formatFormElement的方法,注意,formatformElement 是var,不是def, 这里不能用重载。比如说
formatFormElement = (name, form) =>
          <xml:group> <tr>
          <td>行级别加点啥:{name}</td>
          <td>{form}</td>
          </tr> </xml:group>


到这儿,form的输出过程就差不多了,但是,还差一点东西,<table/>标签呢?<form/>标签呢?
在这个例子里<table/>直接写在了entry.html中,这也许是我们自己实现中需要注意的东西(btw.如果页面不用table控制咋办?)

<form/>是在LiftSession.processSnippet方法的最后处理的,这里会判断snippet中有没有form="xx" 属性,如果有,则生成一个<form/>来包含snippet返回的内容,xx会输出method=xx

好了,打完收工。
分享到:
评论
1 楼 yangzhan 2009-11-19  
最近也在看scala和lift,对下面两点深表同意,也许这两点也是scala和lift难于在项目中推广的原因。
============================================================
2.不好好锻炼一下函数式编程的思维,学习scala/lift实在不是太容易的事情,现在看从java开发者转变到scala的开发者也许没有想象中的容易;3.scala的很多特性也许让写代码变得简单,但是给阅读代码带来的复杂程度也不小;

相关推荐

    Java学习笔记学习笔记

    Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习笔记Java学习...

    2022吴恩达机器学习笔记汇总(共10章节).zip

    2022吴恩达机器学习笔记汇总(共10章节).zip2022吴恩达机器学习笔记汇总(共10章节).zip2022吴恩达机器学习笔记汇总(共10章节).zip2022吴恩达机器学习笔记汇总(共10章节).zip2022吴恩达机器学习笔记汇总(共10章节).zip...

    希沃白板学习笔记.pdf

    希沃白板学习笔记.pdf希沃白板学习笔记.pdf希沃白板学习笔记.pdf希沃白板学习笔记.pdf希沃白板学习笔记.pdf希沃白板学习笔记.pdf希沃白板学习笔记.pdf希沃白板学习笔记.pdf希沃白板学习笔记.pdf

    Springcloud学习笔记.md

    Springcloud学习笔记.md,Springcloud学习笔记.md,Springcloud学习笔记.md,Springcloud学习笔记.md,Springcloud学习笔记.md,Springcloud学习笔记.md,Springcloud学习笔记.md,Springcloud学习笔记.md,Spring...

    人工智能学习笔记,人工智能学习笔记

    人工智能学习笔记,人工智能学习笔记,人工智能学习笔记人工智能学习笔记,人工智能学习笔记,人工智能学习笔记人工智能学习笔记,人工智能学习笔记,人工智能学习笔记人工智能学习笔记,人工智能学习笔记,人工智能...

    CCNA学习笔记 CCNA学习笔记

    CCNA学习笔记 CCNA学习笔记 CCNA学习笔记

    云的学习笔记-云的学习笔记系统-云的学习笔记系统源码-云的学习笔记管理系统-基于ssm的云的学习笔记系统-ssm-java代码

    云的学习笔记-云的学习笔记系统-云的学习笔记系统源码-云的学习笔记管理系统-云的学习笔记管理系统java代码-云的学习笔记系统设计与实现-基于ssm的云的学习笔记系统-基于Web的云的学习笔记系统设计与实现-云的学习...

    云的学习笔记-云的学习笔记系统-云的学习笔记系统源码-云的学习笔记管理系统-基于Web的云的学习笔记系统设计与实现-java代码

    云的学习笔记-云的学习笔记系统-云的学习笔记系统源码-云的学习笔记管理系统-云的学习笔记管理系统java代码-云的学习笔记系统设计与实现-基于ssm的云的学习笔记系统-基于Web的云的学习笔记系统设计与实现-云的学习...

    nginx学习笔记(软件+学习笔记)

    nginx学习笔记(软件+学习笔记) 仅供学习交流! 后续会持续分享相关资源,记得关注哦! nginx学习笔记(软件+学习笔记) 仅供学习交流! 后续会持续分享相关资源,记得关注哦! nginx学习笔记(软件+学习笔记) ...

    docker学习笔记.md

    docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,docker学习笔记,...

    PHP个人学习笔记

    PHP个人学习笔记

    contiki 学习笔记

    Contiki学习笔记:进程、事件、etimer关系 Contiki 实例: Contiki学习笔记:创建两个交互进程 Contiki 主函数剖析: Contiki学习笔记:main函数剖析 Contiki学习笔记:启动一个进程process_start Contiki学习笔记...

    SSH学习笔记7 SSH学习笔记7

    SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记 SSH学习笔记

    ssh学习笔记1 ssh学习笔记1

    ssh学习笔记1 ssh学习笔记1 ssh学习笔记1 ssh学习笔记1 ssh学习笔记1 ssh学习笔记1 ssh学习笔记1

Global site tag (gtag.js) - Google Analytics