readman 的头像

作者:readman

推荐

Lift 中文社区诚招发稿人

三月 14, 2012 分类:Uncategorized

欢迎加入lift 中文社区, 由于我的学习和工作原因,现在希望找有Liftweb和scala经验的人一起写这个社区.有意者请发邮件到readmangroup@gmail.com

readman 的头像

作者:readman

Upload File in LiftScreen

十月 9, 2012 分类:Lift

先发code


package code.snippet
import net.liftweb.http._
import net.liftweb._
import common.Full
import util._
import net.liftweb.http.provider.servlet.HTTPServletContext
import code.model.resume
import java.io._
import net.liftweb.util._
import net.liftweb.common._
import java.util.Date
import code.model._
import code.lib.util._
 
class writingresume extends LiftScreen{
  override protected def hasUploadField = true
  val resumeupload = makeField[Array[Byte], Nothing]("Upload Resume:  ", new Array[Byte](0),
    field => SHtml.fileUpload(fph => storeFile(fph)),
    NothingOtherValueInitializer)
  var filename = ""
  def storeFile (file : FileParamHolder): Box[File] =
  {
    getBaseApplicationPath match
    {
      case Full(appBasePath) =>
      {
        val d:Date = new Date()
        filename = d.getTime+file.fileName
        var uploadDir = new File(appBasePath + "uploads")
        val uploadingFile = new File(uploadDir, filename)
 
        var output = new FileOutputStream(uploadingFile)
        try
        {
          output.write(file.file)
        }
        catch
          {
            case e => println(e)
          }
        finally
        {
          output.close
          output = null
        }
 
        Full(uploadingFile)
      }
      case _ => Empty
    }
  }
  def getBaseApplicationPath: Box[String] =
  {
    LiftRules.context match
    {
      case context: HTTPServletContext =>
      {
        var baseApp: String = context.ctx.getRealPath("/")
 
        if(!baseApp.endsWith(File.separator))
          baseApp = baseApp + File.separator
 
        Full(baseApp)
      }
      case _ => Empty
    }
  }
 
}
 
 
有以下几点需要注意:
  1. override protected def hasUploadField = true 这句话必须有. 为了告诉LiftScreen有上传的field.
  2. val resumeupload = makeField[Array[Byte], Nothing](“Upload Resume:  ”, new Array[Byte](0),field => SHtml.fileUpload(fph => storeFile(fph)),NothingOtherValueInitializer) 因为LiftScreen本身没有一个可以上传的Field, 所以这里要新建立一个field.需要注意的是, fph这里的格式是FileParamHolder, 是一个用来暂存文件的地址, 可以理解为一个指针, new Array[Byte](0)是建立一个新Array用来储存一个文件.
  3. storeFile调用getBaseApplicationPath, 实现了把一个文件储存在一个目录为webapps/updloads的文件夹下. 请注意这里文件夹的位置需要是根目录(webapps)下. getBaseApplicationPath 可以用来找到这个目录的位置.
readman 的头像

作者:readman

Lift 上的 Modal Dialog

九月 2, 2012 分类:Lift

Modal Dialog是现在比较常用的一种提示, 和输入信息的手段. 因为在同一页面上显示, 所以更加user-friendly. 

Lift上的, 我们一般用Jquery UI的插件.blockui, 完成实现.

先用

  <script id="jquery-blockui"  src="/scripts/jquery.blockui.js" type="text/javascript" ></script>

在你想引用modal的页面.

然后在snippet中

try {

    Templates(List("templates-hidden", "post")).map(html => ModalDialog(html, JsObj(("top" -> Str("30%"))))).openOr(Alert("missing template"))
  } catch {
    case error: Exception => Alert("exception: "+error.getMessage)
  } 

 这个code打开了位于templates-hidden下的名为post.html的网页. 并且把他当做一个MOdalDialog来引用.

 

 

readman 的头像

作者:readman

Lift vs play! 2.0

六月 10, 2012 分类:Lift

最近在Google group, 有人提问Lift 与 play! 2.0的选择,以及Stateless和Stateful的选择.我摘出来, 翻译, 供大家做备用.

From DPP:

  • 本质上说, Lift 比 Play 更适合做一个大型的工程.
  • 安全 — Lift的默认设计就非常安全.
    • 在Play中, 开发者必须要担心如何防止Cross Site Scripting Vulnerabilities(脚本脆弱), 特别是Ajax和Web Sockets, 尽管他们已经修复了很多关键页面的XSS问题.
    • 在Play中, 开发者必须要担心页面访问控制(在Lift中, 有他的Sitemap和Menu集成设计).
    • 在Play中, 开发者必须要建立很多的form访问控制和Ajax访问控制, 当你生成每一个form的时候.(在Lift中, 用户是不可能建立一个没有权限的form并且激活一个"假"Ajax请求.)
  • 团队 — Lift的模版和View First的设计模式, 非常友好, 非常简单的就可以让设计者设计出用户满意的HTML5, 更重要的是, 当需要再次开发的时候, 设计者和开发人员可以分享同一个设计模版, 这省去了很多时间用在解释Scala代码给设计者上.(设计者和开发者是2个不同的, 一个是前端, 一个是后端. 这里想表达的是前端和后端的衔接).
  • Comet — Lift有最好的Comet设计. 在Play中, 开发者必须打开一个web socket对每一个页面上的组件, 这让开发者必须处理失去连接, 连接过期等问题. 但是在Lift中, 所有的Comet组件在一个页面上, 都是通过一个连接.页面中组件的更新和服务器同步的, 这是非常重要的,特别是当你的客户端是一些移动设备, 如mobile phone等.
  • Ajax — Lift的Ajax设计,是最简单的. 没有routing, 没有复杂的call back. 只是一行code 搞定.
  • Complex Form Support — Lift的Wizard是最简单的对据有back-button的多页表格的实现, 特别当你想有一个多页的表格在多个浏览器tab中.

以下是Play的优势

  • Play的instant reload设计, 会大大的减少开发时间. 即使使用JRebel, Lift的速度也不会比Play快.
  • Cross-Function: 有时候, 有一些business的设计, 会多模版又一些改变. Lift的view中没有logic, 但是play有.
  • Play是MVC. 如果你的小组人都喜欢MVC.

From Christopher Poile, 关于stateful 和 stateless:

如果你在Play lists中, 你会发现一些人, 他们会装作fanboy对任何一个framework. 他们会说Play 是一个stateless的架构,而且比stateful的架构更容易scale. 这是错误的.

据我所知, 所有的web app都是有state的, 那些极少的,严格的stateless, 我们叫它web serices. 如果你想建立一个web app(一个有用户状态和setting的网站), 它就一定有state. Play是 "stateless" 但是它把所有的session varibles都放入一个product叫 memcached. 或者 Hazelcast. 关键的是, 几乎每一个web app 都需要state. 当一个纯粹的framework 是stateless的时候, 你则需要一些插件,模拟它的state.

最后, 不要让stateful 和stateless的争论动摇. 几乎很少的网站需要考虑 "scaling". 即使你需要scale, 你不会比FourSquare的scale快吧?

readman 的头像

作者:readman

如何用intellij IDEA的scala生成jar文件

五月 13, 2012 分类:Scala

今天写上一篇文章的时候,有人问我这个问题, 我当时就回答说, 请用buildr, 但是他执意觉得IDEA有此功能, 我就google了一下, 果然很复杂.

  1. 准备好project后, 点Project Setting
  2. 找到Artifacts, 点, 然后把鼠标移到jar上,选择From Modules with Dependencies.
  3. 在Main Class中, 键入你的main class, 注意: 这里如果你直接选择, 会出现
  4. 选择 extract to the target jar.
  5. 点下边的Apply.
  6. 找到Build -> Build Artifacts.然后选择build.
  7. Jar文件会出现在文件目录/out/工程名称/下
readman 的头像

作者:readman

一个关于Lift与Mongodb的连接的例子. Lift-mongodb

五月 13, 2012 分类:Lift

请在右边的我的github上下载这个例子, 然后跟着我下边的步骤来运行这个例子.

  1. 下载lift-mongodb的例子.
  2. 下载mongodb. http://www.mongodb.org/downloads. 不管你下载的文件后缀是什么. 请解压缩到一个目录下.
  3. 打开一个Command Line Console in Windows 或者 Terminial in Mac OS X.
  4. 找到mongodb的目录, 然后进入bin目录.
  5. 运行 mongod. 看到如下信息
    Sun May 13 18:29:31 [websvr] admin web console waiting for connections on port 28017
    Sun May 13 18:29:31 [initandlisten] waiting for connections on port 27017
  6. 打开一个新的控制台
  7. 运行 bin目录下的mongo
  8. 然后用你的IDE打开我的例子, 请注意, 我的例子中已经有sbt和idea. 如果你使用sbt或者idea 直接打开即可

来一起看看这个例子:

首先, 在project/build/LiftProject中, 添加

"net.liftweb" %% "lift-mongodb-record" % liftVersion

然后, 看scala/bootstrap.liftweb/Boot中:

   MongoDB.defineDb(
      DefaultMongoIdentifier,
      MongoAddress(MongoHost(), "lift_app")
    )

这句话是添加mongodb的设置进lift. lift_app是数据库的名字.

在code/lib里, 有一个trait, ProtoUser. 这是lift和mongodb的接口.

object firstName extends StringField(this, 32) {
    override def displayName: String = ??("first.name")
  }

这里的??方法, 是一个查询后边是否为字符串, 如果是的话就返回它, 不是的话,在resource/i18n下的liftapp_en_US.properties里编写错误.

剩下的就是一些对table的定义, 这里需要注意的是这个例子,定义了一个方法thePath, 他是用来建立一个list用来保持数据库格式的.

然后在code/model里的User实现了上边的trait.

这是一个html和scala混写的Object, 我个人觉得这里应该严格的执行html和scala code分离的机制, 估计是原作者为了省事,没有用comet写吧.