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

好了,打完收工。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值