hellolift学习笔记(8)

本文介绍了LiftWeb框架中创建条目、数据保存及更新缓存的过程。详细解析了BaseMapper.save方法及其前后置操作,并探讨了MappedField的setFilter功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随着代码的深入,涉及到的liftweb框架实现级别的代码越来越多,马上完全搞明白实现代码的愿望越来越奢侈,所以后续的笔记将侧重于例子中用到功能的解释,侧重框架的使用,只要不影响理解,尽量不再涉及框架实现层的东西。

9.Create An Entry(2--save)

form提交之后涉及到的过程就是采集数据,写入数据库,更新缓存数据。
采集数据的过程由框架来实现,将采集到的数据封装成一个Entry对象,传递给toform时设定的函数。
写入数据库的过程由BaseMapper.save 方法完成(实际是在Mapper中实现,当然其中很多工作又交给了MetaMapper对象去完成),我们所需要做的就是调用一下save方法,或者如果你愿意的话,在保存的过程中插入你自己想要做的一些事情。
例子中我们能看到afterCommit的使用
// Once the transaction is committed, fill in the blog cache with this entry.
override def afterCommit =
((entry: Entry) => {BlogCache.cache ! AddEntry(entry, entry.author.is)}) :: Nil

,相似的还有以下一些函数可以利用
  def beforeValidation: List[A => Unit] = Nil
def beforeValidationOnCreate: List[A => Unit] = Nil
def beforeValidationOnUpdate: List[A => Unit] = Nil
def afterValidation: List[A => Unit] = Nil
def afterValidationOnCreate: List[A => Unit] = Nil
def afterValidationOnUpdate: List[A => Unit] = Nil

def beforeSave: List[A => Unit] = Nil
def beforeCreate: List[(A) => Unit] = Nil
def beforeUpdate: List[(A) => Unit] = Nil

def afterSave: List[(A) => Unit] = Nil
def afterCreate: List[(A) => Unit] = Nil
def afterUpdate: List[(A) => Unit] = Nil

def beforeDelete: List[(A) => Unit] = Nil
def afterDelete: List[(A) => Unit] = Nil


还有一段代码没有看
override def setFilter = notNull _ :: trim _ :: crop _ :: super.setFilter

说实话,这个命名让我对自己的审美观产生了怀疑,哪位大神居然起了这么个名字!?首先,这不是个set方法,其次他的内容也不同于Iterable中的filter方法,估计他的命名原意是,set之前进行的filter工作。我们来看这个方法的原始定义
/**
* A list of functions that transform the value before it is set. The transformations
* are also applied before the value is used in a query. Typical applications
* of this are trimming and/or toLowerCase-ing strings
*/
protected def setFilter: List[FieldType => FieldType] = Nil

这是一个函数列表,每一个函数都接收一个本类型字段,对其加工之后仍然返回一个本类型字段,用以实现流水线似的转换工作。

这个名字倒是说明白了,这个函数的作用,在每次字段被赋值之前都将被这一系列函数加工。MappedField的子类中各自实现了自己使用的filter。

本例中body字段定义的setFilter使得对body字段有了一些限制,比如说crop方法决定了body的值如果大于构造参数的20000,将被截断,注意,这个行为不仅仅体现是表单提交时,即使是在代码中赋值也一样会被截断。

但是Entry的另一个字段title就稍微有些怪异。
object title extends MappedString(this, 128)

这个怪异在于,MappedString的缺省setFilter中并没有crop方法,所以虽然在toForm过程中maxlength(128)会被用来限制输入框的maxLength,但是如果在代码中赋值的话却不会被截断。

解决这个倒也简单,自己重载setFilter,或者用MappedPoliteString代替MappedString,这个类只干了这一件事(我真觉不出这是一个多好的设计)。

现在,我们也基本搞明白了MappedField构造时this之外参数的作用了。不过这里留下了一个疑问,现在的错误都被系统默默的吞掉了,如何给用户提示呢?

ok,只剩下一点点东西了,我快速的把这个过程close掉。

afterCommit:
在理解了viewblog的过程之后,这个afterCommit之后的处理就没有什么新鲜的了:通知BlogCache,缓存博客内容,通知正在关注这个博客的comet刷新内容。
这里也留下了个小疑问,订阅的comet是被记录在了sessions中,但是如果那个页面关闭,这个sessions中的值是何时被清除的呢?

viewentry:
t.save 之后,将跳转到/veiwentry,BlogUtil.viewentry演示了一种有body的snippet类型,body内容将会作为xhtml参数传递进来。
利用net.liftweb.util.BindHelpers.bind方法把指定namespace的标签值替换为合适的内容。
这里的疑问是,替换时为什么要显示的调用toString方法呢,我尝试去掉toString没有发现什么异常。

BlogUtil还有一个_entryview与DynamicBlogView的同名方法完全一致,怀疑是个小疏忽。

把几个疑问单拎出来:
1.现在的属性字段的错误被系统默默的吞掉了,如何给用户提示呢?
2.订阅的comet是被记录在了sessions中,但是如果那个页面关闭,这个sessions中的值是何时被清除的呢?
3.viewentry替换时为什么要显示的调用toString方法呢,我尝试去掉toString没有发现什么异常。

打完,收工!
内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值