Getting started with Lift · Struts Grails Rails PHP JSF Wicket GWT Stripes JAX-RS Spring MVC Play...
Transcript of Getting started with Lift · Struts Grails Rails PHP JSF Wicket GWT Stripes JAX-RS Spring MVC Play...
Getting started with LiftRichard Dallaway, @d6y
lsug.org
Struts
Grails
Rails
PHP
JSF
Wicket
GWT
JAX-RSStripes
Spring MVC
Play Seam
Seaside
Lift
Cocoon
WebObjects
Struts
Grails
Rails
PHP
JSF
Wicket
GWT
JAX-RSStripes
Spring MVC
Play Seam
Seaside
Lift
Cocoon
WebObjects
Zero PlentyWeirdness
☞☞☞
☞☞
http://liftweb.net
Versions
1.0.3 Updated Jan 2010
2.0 M2 Released Feb 2010
both for Scala 2.7.7
lift-base/lift-actorlift-base/lift-commonlift-base/lift-jsonlift-base/lift-utillift-base/lift-webkit
lift-modules/lift-amqplift-modules/lift-facebooklift-modules/lift-imaginglift-modules/lift-jtalift-modules/lift-ldaplift-modules/lift-machinelift-modules/lift-oauthlift-modules/lift-openidlift-modules/lift-osgi
lift-modules/lift-paypallift-modules/lift-testkitlift-modules/lift-textilelift-modules/lift-widgetslift-modules/lift-wizardlift-modules/lift-xmpp
lift-persistence/lift-couchdblift-persistence/lift-jpalift-persistence/lift-mapperlift-persistence/lift-record
$ find . -name lift\* -depth 2 -type d
Agenda
• Part I: View first
• Part II: Doing stuff quickly
• Part III: Ajax
• Part IV: Real time web
The time on this server is: Mon Mar 08 18:40:51 GMT 2010.
<html xmlns="http://www.w3.org/1999/xhtml"><body><h1>Hello world</h1>
<p>The time on this server is: <lift:Time.now> time appears here </lift:Time.now></p>
</body></html>
package com.myproject.snippet
import scala.xml.NodeSeq
class Time {
// My <lift:Time.now /> implementation: def now(xhtml: NodeSeq) = <span>{new java.util.Date()}</span> }
<html xmlns="http://www.w3.org/1999/xhtml"><body><h1>Hello world</h1>
<lift:Time.now><p>It’s <when:day/> at <when:hour/>.</p>
</lift:Time.now>
</body></html>
package com.myproject.snippet
import scala.xml.{NodeSeq,Text}import net.liftweb.util.Helpers._ class Time {
def now(xhtml:NodeSeq) = { val day = "Monday" val hour = "7 o'clock" bind("when", xhtml,
"hour" -> <span>{hour}</span>, "day" -> Text(day) )
}}
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<h1>Hello Canada</h1>
<lift:Olympics.results> <table> <table:rows> <tr> <td><r:country>Country here</r:country></td> <td><r:golds>Gold medal count</r:golds></td> </tr> </table:rows> </table> </lift:Olympics.results>
</body>
</html>
package com.myprojects.snippet
import scala.xml.NodeSeqimport net.liftweb.util.Helpers._ class Olympics {
case class Golds(country: String, medals: Int) def results(xhtml: NodeSeq) = { val vancouver = Golds("CAN", 14) :: Golds("GER", 10) :: Golds("GBR", 1) :: Nil // <table:rows> <r:country/> <r:golds/> </table:rows>
bind("table", xhtml, ! ! "rows" -> vancouver.flatMap( gold =>
bind("r", chooseTemplate("table", "rows", xhtml), "country" -> gold.country,
"golds" -> gold.medals ) )
) }
}
$ mvn archetype:generate \ -DarchetypeCatalog=http://scala-tools.org/
Choose archetype:1: http://scala-tools.org/ -> scala-archetype-simple (A simple scala project)2: http://scala-tools.org/ -> lift-archetype-blank (A blank/empty liftweb project)3: http://scala-tools.org/ -> lift-archetype-basic (A basic liftweb project (with DB, css, ...))Choose a number: (1/2/3):
$ mvn archetype:generate \ -DarchetypeGroupId=net.liftweb \ -DarchetypeArtifactId=lift-archetype-blank \ -DarchetypeVersion=2.0-M2 \ -DremoteRepositories=http://scala-tools.org/repo-releases \ -DgroupId=com.example.proj
package com.brightonbloggers.admin.model
import net.liftweb.common._import net.liftweb.util._import net.liftweb.mapper._import net.liftweb.http._
class Blog extends LongKeyedMapper[Blog] with IdPK {
def getSingleton = Blog object title extends MappedString(this, 20) object url extends MappedString(this, 100) { override def validations = isUrl _ :: super.validations } def isUrl(u:String) = if (url startsWith "http") ! ! ! ! ! ! ! Nil! ! ! ! ! ! else ! ! ! ! ! ! ! List(FieldError(url, S.?("field.url.error"))) }
object Blog extends Blog with LongKeyedMetaMapper[Blog] with CRUDify[Long,Blog] {}
<lift:surround with="default" at="content">
<h1>Ajax blog</h1>
<div id="list">
<lift:Blogs.list> <ul> <directory:entry /> </ul> <directory:new_blog /> </lift:Blogs.list>
</div>
</lift:surround>
package com.brightonbloggers.admin.snippet
import com.brightonbloggers.admin.model.Blog
import scala.xml._import net.liftweb.common._import net.liftweb.mapper._import net.liftweb.http.SHtml._import net.liftweb.http.js.JsCmds._import net.liftweb.util.Helpers._import net.liftweb.http.S._
class Blogs {
def list(xhtml: NodeSeq): NodeSeq = {! def add_new_blog(s: String) = { Blog.create.url(s).title(s).save SetHtml( "list", list(xhtml) ) } bind("directory", xhtml, ! ! "entry" -> Blog.findAll().flatMap(
b => <li>{b.url}</li> ), ! ! "new_blog" -> ajaxText("", add_new_blog _) ) } }
package com.brightonbloggers.admin.snippet
import com.brightonbloggers.admin.model.Blog
import scala.xml._import net.liftweb.common._import net.liftweb.mapper._import net.liftweb.http.SHtml._import net.liftweb.http.js.JsCmds._import net.liftweb.util.Helpers._import net.liftweb.http.S._
class Blogs {
def list(xhtml: NodeSeq): NodeSeq = {! def add_new_blog(s: String) = { Blog.create.url(s).title(s).save SetHtml("list", list(xhtml) ) } def update_blog(blog: Blog)(new_value: String) = { blog.url(new_value).save SetHtml("list", list(xhtml) ) } def click_to_edit(blog: Blog) : NodeSeq = !! swappable( <li>{blog.url}</li>, !! ! ajaxText(blog.url, update_blog(blog) _ ) ) bind("directory", xhtml, !! "entry" -> Blog.findAll().flatMap( click_to_edit _ ), !! "new_blog" -> ajaxText("", add_new_blog _) ) }}
Client
Server
Time
Browser UI
COMET Client
User Activity
Client Processing
Dis
play
Dis
play
Dis
play
Comet Event Bus
Initialization Dat
a P
ush
Dat
a P
ush
Dat
a P
ush
Dis
play
Dis
play
Dat
a P
ush
Dat
a P
ush
Server-Side Processing
Eve
nt
Eve
nt
Eve
nt
Eve
nt
Eve
nt
def list(xhtml: NodeSeq): NodeSeq = {! def countable(blog: Blog) : NodeSeq = ! <li>{link("/static/list", () => { StatsServer ! blog }, Text(blog.url)) }</li> bind("directory", xhtml, ! ! "entry" -> Blog.findAll().flatMap(countable _) )
package com.brightonbloggers.admin.comet
import net.liftweb.http._import net.liftweb.common._import net.liftweb.util.Helpers._import net.liftweb.http.js._import net.liftweb.actor._import net.liftweb.http.js.JsCmds._import scala.xml._
object StatsServer extends LiftActor with ListenerManager { var count = 0 override def lowPriority = { case b => count = count + 1 updateListeners() } def createUpdate = count}
// <lift:comet type=”StatsWatch” />class StatsWatch extends CometActor with CometListenee {
def registerWith = StatsServer override def render = <div id="total">0</div> override def lowPriority = { case count: Int => partialUpdate(SetHtml("total", Text(count.toString))) } }
Thank you.
• Lift book: http://groups.google.com/group/the-lift-book
• Liftweb.net: Wiki, mailing list, getting started guide
• Visit lsug.org, join the meetup.com group
apress discount code
LONDONSCALAUQUCUAVGLT
Next Meeting
Traits & Mixins Kevin
Monday 12 April
Here, Skillsmatter