Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
lsug-lift.pdf
Search
Richard Dallaway
March 08, 2010
Programming
0
30
lsug-lift.pdf
London Scala User Group introduction to Lift web development, 8 March 2010.
Richard Dallaway
March 08, 2010
Tweet
Share
More Decks by Richard Dallaway
See All by Richard Dallaway
AI Roadmap
d6y
0
48
Voice to guide "difficult" recycling queries
d6y
0
63
Brighton Java: Day in the life...
d6y
0
230
Day in the Life of a Functional Programmer
d6y
0
640
Exoplanet Safari
d6y
1
460
Types Working For You
d6y
1
2.7k
Towards Browser and Server Utopia with Scala.js: an example using CRDTs
d6y
0
7.7k
Code Review Gems
d6y
1
2k
Woot for Lift
d6y
2
3.3k
Other Decks in Programming
See All in Programming
AWS re:Invent 2025参加 直前 Seattle-Tacoma Airport(SEA)におけるハードウェア紛失インシデントLT
tetutetu214
2
110
AIエージェントのキホンから学ぶ「エージェンティックコーディング」実践入門
masahiro_nishimi
5
400
生成AIを使ったコードレビューで定性的に品質カバー
chiilog
1
260
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
540
AI & Enginnering
codelynx
0
110
そのAIレビュー、レビューしてますか? / Are you reviewing those AI reviews?
rkaga
6
4.5k
CSC307 Lecture 07
javiergs
PRO
0
550
AIで開発はどれくらい加速したのか?AIエージェントによるコード生成を、現場の評価と研究開発の評価の両面からdeep diveしてみる
daisuketakeda
1
2.4k
AIと一緒にレガシーに向き合ってみた
nyafunta9858
0
190
なるべく楽してバックエンドに型をつけたい!(楽とは言ってない)
hibiki_cube
0
140
AIによるイベントストーミング図からのコード生成 / AI-powered code generation from Event Storming diagrams
nrslib
2
1.9k
16年目のピクシブ百科事典を支える最新の技術基盤 / The Modern Tech Stack Powering Pixiv Encyclopedia in its 16th Year
ahuglajbclajep
5
1k
Featured
See All Featured
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
9.9k
How to Ace a Technical Interview
jacobian
281
24k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
380
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
180
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
79
Discover your Explorer Soul
emna__ayadi
2
1.1k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
280
Practical Orchestrator
shlominoach
191
11k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
1
99
AI Search: Where Are We & What Can We Do About It?
aleyda
0
6.9k
Thoughts on Productivity
jonyablonski
74
5k
Automating Front-end Workflow
addyosmani
1371
200k
Transcript
Getting started with Lift Richard Dallaway, @d6y
[email protected]
lsug.org
None
Struts Grails Rails PHP JSF Wicket GWT JAX-RS Stripes Spring
MVC Play Seam Seaside Lift Cocoon WebObjects
Struts Grails Rails PHP JSF Wicket GWT JAX-RS Stripes Spring
MVC Play Seam Seaside Lift Cocoon WebObjects Zero Plenty Weirdness
‛ ‛ ‛ ‛ http://liftweb.net
Versions 1.0.3 Updated Jan 2010 2.0 M2 Released Feb 2010
both for Scala 2.7.7
None
None
lift-base/lift-actor lift-base/lift-common lift-base/lift-json lift-base/lift-util lift-base/lift-webkit lift-modules/lift-amqp lift-modules/lift-facebook lift-modules/lift-imaging lift-modules/lift-jta lift-modules/lift-ldap
lift-modules/lift-machine lift-modules/lift-oauth lift-modules/lift-openid lift-modules/lift-osgi lift-modules/lift-paypal lift-modules/lift-testkit lift-modules/lift-textile lift-modules/lift-widgets lift-modules/lift-wizard lift-modules/lift-xmpp lift-persistence/lift-couchdb lift-persistence/lift-jpa lift-persistence/lift-mapper lift-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) ) } }
None
<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.NodeSeq import 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 ) ) ) } }
None
$ 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>
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 _) ) } }
None
$MJFOU 4FSWFS 5JNF #SPXTFS6* $0.&5$MJFOU User Activity Client Processing Display
Display Display Comet Event Bus Initialization Data Push Data Push Data Push Display Display Data Push Data Push Server-Side Processing Event Event Event Event Event
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
None