W-JAX 09 - Lift

Preview:

DESCRIPTION

Lift - Das Web-Framework für Scala

Citation preview

Copyright WeigleWilczek 2009

Das Web-Framework für ScalaHeiko Seeberger

2

“Lift is the only new framework in the last four years to offer fresh and innovative approaches to web development. It's not just some

incremental improvements over the status quo, it redefines the state of the art. If you are a web developer, you should learn Lift ...”

WARUM SIND WIR EIGENTLICH HIER?

Michael Galpin, Developer, eBay

WARUM NOCH EIN WEB-FRAMEWORK?

3

Lift pickt Rosinen von anderen Frameworks

Lift bringt eigene innovative Ansätze

DEMO: CHAT MIT 20 ZEILEN SCALA CODE

4

FÜR’S PROTOKOLL

5

• Projekt generieren mit mvn archetype:generate ...

• ChatServer.scala anlegen

• Chat.scala anlegen

• chat.xhtml Template anlegen

• In Boot.scala neues Menu zur SiteMap hinzufügen

DIE ANFÄNGE

6

2006

David Pollak Einfach zu benutzen

Sicher

Einfach zu deployenKeep the meaning

with the bytes

Scala with Sails

HEUTE

7

Lift 1.1 vor der Tür Sehr rege Community

Etliche Sites powered by Lift 32 Committer

FEATURES IM ANGEBOT

8

Templates

Persistenz

AJAX

Comet

User Management

Sitemap

“MUSTERLÖSUNG”

9

WEITERE FEATURES (UNVOLLSTÄNDIG)

10

JSON

JPA und JTA

Textile

Wizards

PayPay

AMPQ

OpenID

OSGi

TEMPLATES

11

<html> <head> <title>kix</title> ... <body> <div class="container"> ... <div class="span-18 last"> <lift:Msgs showAll="true"/> <lift:bind name="content"/> ... </div> <div class="span-12" style="text-align: center;"> <img src="/images/pbww.png"/> </div> ...

mit Lift-Tags

WIE SCHREIBEN WIR TEMPLATES?

12

In XHTML

TEMPLATES VERSCHACHTELN

13

<lift:surround ...>

<lift:bind ... />

class Games { def upcoming5(xhtml: NodeSeq) = bind("games", xhtml, "list" -> bindGames(Game upcoming 5, xhtml))

<lift:surround with="default" at="content"> ... <lift:Games.upcoming5> <games:list> <tr game:class=""> <td><span game:id=""><game:action/></span></td> <td><game:date/></td> <td><game:group/></td> <td><game:location/></td> <td><game:teams/></td> ...

SNIPPETS EINBINDEN

14

Snippet-Tag

Platzhalter imNamespace game

Snippet

class Games {

def upcoming5(xhtml: NodeSeq) = bind("games", xhtml, "list" -> bindGames(Game upcoming 5, xhtml))

private def bindGames(games: List[Game], xhtml: NodeSeq) = { val oddOrEven = OddOrEven() games flatMap { game => bind("game", chooseTemplate("games", "list", xhtml), "date" -> format(game.date.is, locale), "group" -> game.group.is.toString, "location" -> game.location.is, ...

SNIPPETS UND BINDING

15

Platzhalter ersetzen

LIVE DEMO

16

SITEMAP

17

MENÜS UND ZUGRIFFSKONTROLLE

18

SITEMAP ANLEGEN

19

val ifAdmin = If(() => User.superUser_?, () => RedirectResponse("/index"))

val homeMenu = Menu(Loc("home", ("index" :: Nil) -> false, "Home"))...val adminMenu = Menu(Loc("admin", ("admin" :: Nil) -> true, "Admin", ifAdmin), adminSubMenu: _*)

val menus = homeMenu :: ... adminMenu :: User.sitemap

LiftRules setSiteMap SiteMap(menus : _*)

MENÜS ANZEIGEN

20

<html> <head> <title>kix</title> ... <body> <div class="container"> ... <div class="span-5"> <div class="menu"> <lift:Menu.builder/> </div> ...

LIVE DEMO

21

PERSISTENZ

22

MAPPER

23

class Game extends LongKeyedMapper[Game] with IdPK {

object group extends MappedEnum(this, Group) { override def displayName = ?("Group") }

object team1 extends MappedTeam(this, "Team 1")

object team2 extends MappedTeam(this, "Team 2")

object date extends MappedDateTime(this) { override def displayName = ?("Date") }

object location extends MappedString(this, 100) { override def displayName = ?("Location") } ... Keep the meaning

with the bytes

CRUD SUPPORT

24

... with CRUDify[Long, Game]

SCHEMA ANLEGEN

25

val dbVendor = new StandardDBVendor(Props get "db.driver" openOr "org.h2.Driver", Props get "db.url" openOr "jdbc:h2:kix", Empty, Empty) { override def maxPoolSize = Props getInt "db.pool.size" openOr 3}DB.defineConnectionManager(DefaultConnectionIdentifier, dbVendor)Schemifier.schemify(true, Log.infoF _, Team, Game, Result, Tip, User)

LIVE DEMO

26

USER MANAGEMENT

27

CLAUSTHALER-PRINZIP

28

MORE THAN JUST CRUD

29

class User extends MegaProtoUser[User] {

override def shortName = { val s = super.shortName val i = s indexOf "@" if (i == -1) s else s.substring(0, i) }

override def firstNameDisplayName = ?("Name")

object points extends MappedInt(this)}

LIVE DEMO

30

AJAX SUPPORT

31

BEISPIEL: LISTEN-ELEMENTE LÖSCHEN

32

SCALA API FÜR AJAX

33

def editDelete(tip: Tip) = { def delete = { Tip delete_! tip SetHtml(tip.id.is.toString, NodeSeq.Empty) } renderEditDelete(tip, delete _)}

private def renderEditDelete(tip: Tip, jsCmd: () => JsCmd) = link("/tips/edit", () => currentTip(Full(tip)), editImg) ++ Text("") ++ ajaxDeleteImg(ajaxInvoke(jsCmd))

LIVE DEMO

34

COMET SUPPORT

35

CHATTEN LEICHT GEMACHT

36

FRAGEN / DISKUSSION

37