SlideShare una empresa de Scribd logo
1 de 39
ng with
2.0




      Siarzh Miadzvedzeu @siarzh
is

“a web framework for a new era”

                   &

“designed by web developers
 for web developers”
                   Guillaume Bort, creator
0.x   how it was
1.0   how it was
1.2   how it was
2.0   how it was
2.0            is

•   full stack web framework for JVM
•   high-productive
•   asynch & reactive
•   stateless
•   HTTP-centric
•   typesafe
•   scalable
•   open source
•   part of Typesafe Stack 2.0
2.0             is fun and high-productive


•   fast turnaround: change you code and hit reload! :)
•   browser error reporting
•   db evolutions
•   modular and extensible via plugins
•   minimal bootstrap
•   integrated test framework
•   easy cloud deployment (e.g. Heroku)
2.0            is asynch & reactive


•   WebSockets
•   Comet
•   HTTP 1.1 chuncked responses
•   composable streams handling
•   based on event-driven, non-blocking Iteratee I/O
2.0            is HTTP-centric


•   based on HTTP and stateless
•   doesn't fight HTTP or browser
•   clean & easy URL design (via routes)
•   designed to work with HTML5

          “When a web framework starts an architecture fight
          with the web, the framework loses.”
2.0                 is typesafe where it matters




                                      }
•   templates
•   routes
•   configs
•   javascript (via Goggle Closure)
                                          all are compiled
•   LESS stylesheets
•   CoffeeScript

                + browser error reporting
2.0                 getting started

1. download Play 2.0 binary package


2. add play to your PATH:
                              export PATH=$PATH:/path/to/play20


3. create new project:
                              $ play new myFirstApp



4. run the project:
                              $ cd myFirstApp
                              $ play run
2.0                  config
                                             single conf/application.conf:
# This is the main configuration file for the application.

# The application languages
# ~~~~~
application.langs="en"

# Database configuration
# ~~~~~
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
#
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
# db.default.user=sa
# db.default.password=

# Evolutions
# ~~~~~
# You can disable evolutions if needed
# evolutionplugin=disabled
...
2.0        IDE support
Eclipse:             $ eclipsify


IntelliJ IDEA:       $ idea



Netbeans:        add to plugins.sbt:
                 resolvers += {
                     "remeniuk repo" at "http://remeniuk.github.com/maven"
                 }


                 libraryDependencies += {
                   "org.netbeans" %% "sbt-netbeans-plugin" % "0.1.4"
                 }



                     $ play netbeans
2.0                  and SBT
              Build.scala                                     plugins.sbt
import sbt._                                  addSbtPlugin("play" % "sbt-plugin" % "2.0")
import Keys._
import PlayProject._

object ApplicationBuild extends Build {

val appName            = "Your application"
val appVersion         = "1.0"

val appDependencies = Seq(
 // Add your project dependencies here,
)

val main = PlayProject(
 appName, appVersion, appDependencies,
  mainLang = SCALA
).settings(
 // Add your own project settings here
)

}
2.0               routes
# Home page
GET /                     controllers.Application.homePage()
GET /home                 controllers.Application.show(page = "home")

# Display a client.
GET /clients/all          controllers.Clients.list()
GET /clients/:id          controllers.Clients.show(id: Long)

# Pagination links, like /clients?page=3
GET /clients              controllers.Clients.list(page: Int ?= 1)

# With regex
GET /orders/$id<[0-9]+>   controllers.Orders.show(id: Long)

# 'name' is all the rest part of the url including '/' symbols
GET /files/*name          controllers.Application.download(name)
2.0                reversed routing

# Hello action
GET /helloBob    controllers.Application.helloBob
GET /hello/:name controllers.Application.hello(name)




// Redirect to /hello/Bob
def helloBob = Action {
  Redirect( routes.Application.hello("Bob") )
}
2.0                   actions
action: (play.api.mvc.Request => play.api.mvc.Result)


Action(parse.text) { request =>
  Ok("<h1>Got: " + request.body + "</h1>").as(HTML).withSession(
                session + ("saidHello" -> "yes")
              ).withHeaders(
                CACHE_CONTROL -> "max-age=3600",
                ETAG -> "xx"
              ).withCookies(
                Cookie("theme", "blue")
              )
}

val   notFound = NotFound
val   pageNotFound = NotFound(<h1>Page not found</h1>)
val   badRequest = BadRequest(views.html.form(formWithErrors))
val   oops = InternalServerError("Oops")
val   anyStatus = Status(488)("Strange response type")
2.0                controllers

package controllers

import play.api.mvc._

object Application extends Controller {

    def index = Action {
      Ok("It works!")
    }

    def hello(name: String) = Action {
      Ok("Hello " + name)
    }

    def goodbye(name: String) = TODO

}
2.0              templates
                                                      …are just functions ;)
views/main.scala.html:     @(title: String)(content: Html)
                           <!DOCTYPE html>
                           <html>
                           <head>
                            <title>@title</title>
                           </head>
                           <body>
                            <section class="content">@content</section>
                           </body>
                           </html>

views/hello.scala.html:    @(name: String = “Guest”)

                           @main(title = "Home") {
                           <h1>Welcome @name! </h1>
                           }




then from Scala class:     val html = views.html.Application.hello(name)
2.0                database evolutions
conf/evolutions/${x}.sql:


        # Add Post

        # --- !Ups
        CREATE TABLE Post (
          id bigint(20) NOT NULL AUTO_INCREMENT,
          title varchar(255) NOT NULL,
          content text NOT NULL,
          postedAt date NOT NULL,
          author_id bigint(20) NOT NULL,
          FOREIGN KEY (author_id) REFERENCES User(id),
          PRIMARY KEY (id)
        );

        # --- !Downs
        DROP TABLE Post;
2.0   browser error reporting
2.0                   access SQL data via Anorm
import anorm._

DB.withConnection { implicit c =>

    val selectCountries = SQL("Select * from Country")

    // Transform the resulting Stream[Row] to a List[(String,String)]
    val countries = selectCountries().map(row =>
      row[String]("code") -> row[String]("name")
    ).toList
}


// using Parser API
import anorm.SqlParser._

val count: Long = SQL("select count(*) from Country").as(scalar[Long].single)

val result:List[String~Int] = {
  SQL("select * from Country")
  .as(get[String]("name")~get[Int]("population") map { case n~p => (n,p) } *)
}
2.0                     and Akka
 def index = Action {          // using actors, coverting Akka Future to Play Promise
  Async {
         (myActor ? "hello").mapTo[String].asPromise.map { response =>
           Ok(response)
         }
     }
 }


 def index = Action {          // execute some task asynchronously
  Async {
         Akka.future { longComputation() }.map { result =>
           Ok("Got " + result)
         }
     }
 }

// schedule sending message 'tick' to testActor every 30 minutes
Akka.system.scheduler.schedule(0 seconds, 30 minutes, testActor, "tick")

// schedule a single task
Akka.system.scheduler.scheduleOnce(10 seconds) {
  file.delete()
}
2.0                 streaming response
def index = Action {

    val file = new java.io.File("/tmp/fileToServe.pdf")
    val fileContent: Enumerator[Array[Byte]] = Enumerator.fromFile(file)

  SimpleResult(
    header = ResponseHeader(200, Map(CONTENT_LENGTH ->
file.length.toString)),
        body = fileContent
    )
}


// Play has a helper for the above:


def index = Action {
  Ok.sendFile(new java.io.File("/tmp/fileToServe.pdf"))
}
2.0                  chunked results
def index = Action {

    val data = getDataStream
    val dataContent: Enumerator[Array[Byte]] = Enumerator.fromStream(data)

    ChunkedResult(
     header = ResponseHeader(200),
        chunks = dataContent
    )
}


// Play has a helper for the ChunkedResult above:

Ok.stream(dataContent)
2.0                  Comet
lazy val clock: Enumerator[String] = {
  val dateFormat = new SimpleDateFormat("HH mm ss")

     Enumerator.fromCallback { () =>
       Promise.timeout(Some(dateFormat.format(new Date)), 100 milliseconds)
     }
 }

 def liveClock = Action {
   Ok.stream(clock &> Comet(callback = "parent.clockChanged"))
 }

and then in template:
<script type="text/javascript" charset="utf-8">
 var clockChanged = function(time) { // do something }
</script>

<iframe id="comet" src="@routes.Application.liveClock.unique"></iframe>
2.0             WebSockets

just another action in controller:

   def index = WebSocket.using[String] { request =>

       // Log events to the console
       val in = Iteratee.foreach[String](println).mapDone { _ =>
         println("Disconnected")
       }

       // Send a single 'Hello!' message
       val out = Enumerator("Hello!")

       (in, out)
   }
2.0   caching API
      by default uses EHCache, configurable via plugins


      Cache.set("item.key", connectedUser)


      val user: User = Cache.getOrElse[User]("item.key") {
        User.findById(connectedUser)
      }



      // cache HTTP response
      def index = Cached("homePage",600) {
        Action {
          Ok("Hello world")
        }
      }
2.0                 i18n

conf/application.conf:   application.langs="en,en-US,fr"


conf/messages.en:
                         home.title=File viewer
                         files.summary=The disk {1} contains {0} file(s).



 from Scala class:       val title   = Messages("home.title")
                         val titleFR = Messages("home.title")(Lang(“fr"))
                         val summary = Messages("files.summary", d.files.length, d.name)

  from template:         <h1>@Messages("home.title")</h1>
2.0                        testing
                                                   …using specs2 by default
"Computer model" should {


    "be retrieved by id" in {
     running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {

            val Some(macintosh) = Computer.findById(21)


            macintosh.name must equalTo("Macintosh")
            macintosh.introduced must beSome.which(dateIs(_, "1984-01-24"))

        }
    }
}
2.0             testing templates


 "render index template" in {
   val html = views.html.index("Coco")

     contentType(html) must equalTo("text/html")
     contentAsString(html) must contain("Hello Coco")
 }
2.0               testing controllers


"respond to the index Action" in {
  val result = controllers.Application.index("Bob")(FakeRequest())

    status(result) must equalTo(OK)
    contentType(result) must beSome("text/html")
    charset(result) must beSome("utf-8")
    contentAsString(result) must contain("Hello Bob")
}
2.0              testing routes

"respond to the index Action" in {
  val Some(result) = routeAndCall(FakeRequest(GET, "/Bob"))

    status(result) must equalTo(OK)
    contentType(result) must beSome("text/html")
    charset(result) must beSome("utf-8")
    contentAsString(result) must contain("Hello Bob")
}
2.0               testing server


"run in a server" in {
  running(TestServer(3333)) {

        await( WS.url("http://localhost:3333").get ).status must equalTo(OK)

    }
}
2.0                 testing with browser
                                 …using Selenium WebDriver with FluentLenium

"run in a browser" in {
    running(TestServer(3333), HTMLUNIT) { browser =>

        browser.goTo("http://localhost:3333")
        browser.$("#title").getTexts().get(0) must equalTo("Hello Guest")

        browser.$("a").click()

        browser.url must equalTo("http://localhost:3333/Coco")
        browser.$("#title").getTexts().get(0) must equalTo("Hello Coco")


    }
}
2.0   Demo
2.0         Resources

http://www.playframework.org/
https://github.com/playframework/Play20/wiki
http://www.parleys.com/#st=5&id=3143&sl=4
http://www.parleys.com/#st=5&id=3144&sl=13
http://www.parleys.com/#id=3081&st=5
http://vimeo.com/41094673
2.0   Questions


         ?

Más contenido relacionado

La actualidad más candente

Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4DEVCON
 
OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010ikailan
 
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...Ryan Weaver
 
HTML5 JavaScript APIs
HTML5 JavaScript APIsHTML5 JavaScript APIs
HTML5 JavaScript APIsRemy Sharp
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your AppLuca Mearelli
 
Node.js in action
Node.js in actionNode.js in action
Node.js in actionSimon Su
 
Python Code Camp for Professionals 2/4
Python Code Camp for Professionals 2/4Python Code Camp for Professionals 2/4
Python Code Camp for Professionals 2/4DEVCON
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesLindsay Holmwood
 
Keeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackKeeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackIgnacio Martín
 
REST with Eve and Python
REST with Eve and PythonREST with Eve and Python
REST with Eve and PythonPiXeL16
 
Phoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるPhoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるTakahiro Kobaru
 
Filling the flask
Filling the flaskFilling the flask
Filling the flaskJason Myers
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiPraveen Puglia
 

La actualidad más candente (20)

Presentation
PresentationPresentation
Presentation
 
Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4Python Code Camp for Professionals 1/4
Python Code Camp for Professionals 1/4
 
WebGUI Developers Workshop
WebGUI Developers WorkshopWebGUI Developers Workshop
WebGUI Developers Workshop
 
Intro to-ant
Intro to-antIntro to-ant
Intro to-ant
 
Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
Ant
AntAnt
Ant
 
OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010
 
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
 
HTML5 JavaScript APIs
HTML5 JavaScript APIsHTML5 JavaScript APIs
HTML5 JavaScript APIs
 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your App
 
Node.js in action
Node.js in actionNode.js in action
Node.js in action
 
Python Code Camp for Professionals 2/4
Python Code Camp for Professionals 2/4Python Code Camp for Professionals 2/4
Python Code Camp for Professionals 2/4
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websites
 
Keeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and WebpackKeeping the frontend under control with Symfony and Webpack
Keeping the frontend under control with Symfony and Webpack
 
CodeIgniter 3.0
CodeIgniter 3.0CodeIgniter 3.0
CodeIgniter 3.0
 
REST with Eve and Python
REST with Eve and PythonREST with Eve and Python
REST with Eve and Python
 
Scala active record
Scala active recordScala active record
Scala active record
 
Phoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってるPhoenix + Reactで 社内システムを 密かに作ってる
Phoenix + Reactで 社内システムを 密かに作ってる
 
Filling the flask
Filling the flaskFilling the flask
Filling the flask
 
A re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbaiA re introduction to webpack - reactfoo - mumbai
A re introduction to webpack - reactfoo - mumbai
 

Similar a Play!ng with scala

Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexyananelson
 
Using and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareUsing and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareAlona Mekhovova
 
Ruby MVC from scratch with Rack
Ruby MVC from scratch with RackRuby MVC from scratch with Rack
Ruby MVC from scratch with RackDonSchado
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensionserwanl
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on AndroidSven Haiges
 
Web Components With Rails
Web Components With RailsWeb Components With Rails
Web Components With RailsBoris Nadion
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkIndicThreads
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Frameworkvhazrati
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
Nodejs Explained with Examples
Nodejs Explained with ExamplesNodejs Explained with Examples
Nodejs Explained with ExamplesGabriele Lana
 
Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02Sunny Gupta
 
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディングXitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディングscalaconfjp
 
Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Ngoc Dao
 
Writing HTML5 Web Apps using Backbone.js and GAE
Writing HTML5 Web Apps using Backbone.js and GAEWriting HTML5 Web Apps using Backbone.js and GAE
Writing HTML5 Web Apps using Backbone.js and GAERon Reiter
 

Similar a Play!ng with scala (20)

Html5 For Jjugccc2009fall
Html5 For Jjugccc2009fallHtml5 For Jjugccc2009fall
Html5 For Jjugccc2009fall
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexy
 
Using and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middlewareUsing and scaling Rack and Rack-based middleware
Using and scaling Rack and Rack-based middleware
 
5.node js
5.node js5.node js
5.node js
 
Ruby MVC from scratch with Rack
Ruby MVC from scratch with RackRuby MVC from scratch with Rack
Ruby MVC from scratch with Rack
 
Paris js extensions
Paris js extensionsParis js extensions
Paris js extensions
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Codegnitorppt
CodegnitorpptCodegnitorppt
Codegnitorppt
 
CouchDB on Android
CouchDB on AndroidCouchDB on Android
CouchDB on Android
 
Play 2.0
Play 2.0Play 2.0
Play 2.0
 
Web Components With Rails
Web Components With RailsWeb Components With Rails
Web Components With Rails
 
Overview Of Lift Framework
Overview Of Lift FrameworkOverview Of Lift Framework
Overview Of Lift Framework
 
Overview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web FrameworkOverview of The Scala Based Lift Web Framework
Overview of The Scala Based Lift Web Framework
 
Scala based Lift Framework
Scala based Lift FrameworkScala based Lift Framework
Scala based Lift Framework
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
Nodejs Explained with Examples
Nodejs Explained with ExamplesNodejs Explained with Examples
Nodejs Explained with Examples
 
Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02Nodejsexplained 101116115055-phpapp02
Nodejsexplained 101116115055-phpapp02
 
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディングXitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
Xitrum Web Framework Live Coding Demos / Xitrum Web Framework ライブコーディング
 
Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014Xitrum @ Scala Matsuri Tokyo 2014
Xitrum @ Scala Matsuri Tokyo 2014
 
Writing HTML5 Web Apps using Backbone.js and GAE
Writing HTML5 Web Apps using Backbone.js and GAEWriting HTML5 Web Apps using Backbone.js and GAE
Writing HTML5 Web Apps using Backbone.js and GAE
 

Último

Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterMydbops
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxLoriGlavin3
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Farhan Tariq
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI AgeCprime
 

Último (20)

Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Scale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL RouterScale your database traffic with Read & Write split using MySQL Router
Scale your database traffic with Read & Write split using MySQL Router
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptxThe Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
The Role of FIDO in a Cyber Secure Netherlands: FIDO Paris Seminar.pptx
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...Genislab builds better products and faster go-to-market with Lean project man...
Genislab builds better products and faster go-to-market with Lean project man...
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
A Framework for Development in the AI Age
A Framework for Development in the AI AgeA Framework for Development in the AI Age
A Framework for Development in the AI Age
 

Play!ng with scala

  • 1. ng with 2.0 Siarzh Miadzvedzeu @siarzh
  • 2. is “a web framework for a new era” & “designed by web developers for web developers” Guillaume Bort, creator
  • 3. 0.x how it was
  • 4. 1.0 how it was
  • 5. 1.2 how it was
  • 6. 2.0 how it was
  • 7. 2.0 is • full stack web framework for JVM • high-productive • asynch & reactive • stateless • HTTP-centric • typesafe • scalable • open source • part of Typesafe Stack 2.0
  • 8. 2.0 is fun and high-productive • fast turnaround: change you code and hit reload! :) • browser error reporting • db evolutions • modular and extensible via plugins • minimal bootstrap • integrated test framework • easy cloud deployment (e.g. Heroku)
  • 9. 2.0 is asynch & reactive • WebSockets • Comet • HTTP 1.1 chuncked responses • composable streams handling • based on event-driven, non-blocking Iteratee I/O
  • 10. 2.0 is HTTP-centric • based on HTTP and stateless • doesn't fight HTTP or browser • clean & easy URL design (via routes) • designed to work with HTML5 “When a web framework starts an architecture fight with the web, the framework loses.”
  • 11. 2.0 is typesafe where it matters } • templates • routes • configs • javascript (via Goggle Closure) all are compiled • LESS stylesheets • CoffeeScript + browser error reporting
  • 12. 2.0 getting started 1. download Play 2.0 binary package 2. add play to your PATH: export PATH=$PATH:/path/to/play20 3. create new project: $ play new myFirstApp 4. run the project: $ cd myFirstApp $ play run
  • 13. 2.0 config single conf/application.conf: # This is the main configuration file for the application. # The application languages # ~~~~~ application.langs="en" # Database configuration # ~~~~~ # You can declare as many datasources as you want. # By convention, the default datasource is named `default` # db.default.driver=org.h2.Driver db.default.url="jdbc:h2:mem:play" # db.default.user=sa # db.default.password= # Evolutions # ~~~~~ # You can disable evolutions if needed # evolutionplugin=disabled ...
  • 14. 2.0 IDE support Eclipse: $ eclipsify IntelliJ IDEA: $ idea Netbeans: add to plugins.sbt: resolvers += { "remeniuk repo" at "http://remeniuk.github.com/maven" } libraryDependencies += { "org.netbeans" %% "sbt-netbeans-plugin" % "0.1.4" } $ play netbeans
  • 15. 2.0 and SBT Build.scala plugins.sbt import sbt._ addSbtPlugin("play" % "sbt-plugin" % "2.0") import Keys._ import PlayProject._ object ApplicationBuild extends Build { val appName = "Your application" val appVersion = "1.0" val appDependencies = Seq( // Add your project dependencies here, ) val main = PlayProject( appName, appVersion, appDependencies, mainLang = SCALA ).settings( // Add your own project settings here ) }
  • 16. 2.0 routes # Home page GET / controllers.Application.homePage() GET /home controllers.Application.show(page = "home") # Display a client. GET /clients/all controllers.Clients.list() GET /clients/:id controllers.Clients.show(id: Long) # Pagination links, like /clients?page=3 GET /clients controllers.Clients.list(page: Int ?= 1) # With regex GET /orders/$id<[0-9]+> controllers.Orders.show(id: Long) # 'name' is all the rest part of the url including '/' symbols GET /files/*name controllers.Application.download(name)
  • 17. 2.0 reversed routing # Hello action GET /helloBob controllers.Application.helloBob GET /hello/:name controllers.Application.hello(name) // Redirect to /hello/Bob def helloBob = Action { Redirect( routes.Application.hello("Bob") ) }
  • 18. 2.0 actions action: (play.api.mvc.Request => play.api.mvc.Result) Action(parse.text) { request => Ok("<h1>Got: " + request.body + "</h1>").as(HTML).withSession( session + ("saidHello" -> "yes") ).withHeaders( CACHE_CONTROL -> "max-age=3600", ETAG -> "xx" ).withCookies( Cookie("theme", "blue") ) } val notFound = NotFound val pageNotFound = NotFound(<h1>Page not found</h1>) val badRequest = BadRequest(views.html.form(formWithErrors)) val oops = InternalServerError("Oops") val anyStatus = Status(488)("Strange response type")
  • 19. 2.0 controllers package controllers import play.api.mvc._ object Application extends Controller { def index = Action { Ok("It works!") } def hello(name: String) = Action { Ok("Hello " + name) } def goodbye(name: String) = TODO }
  • 20. 2.0 templates …are just functions ;) views/main.scala.html: @(title: String)(content: Html) <!DOCTYPE html> <html> <head> <title>@title</title> </head> <body> <section class="content">@content</section> </body> </html> views/hello.scala.html: @(name: String = “Guest”) @main(title = "Home") { <h1>Welcome @name! </h1> } then from Scala class: val html = views.html.Application.hello(name)
  • 21. 2.0 database evolutions conf/evolutions/${x}.sql: # Add Post # --- !Ups CREATE TABLE Post ( id bigint(20) NOT NULL AUTO_INCREMENT, title varchar(255) NOT NULL, content text NOT NULL, postedAt date NOT NULL, author_id bigint(20) NOT NULL, FOREIGN KEY (author_id) REFERENCES User(id), PRIMARY KEY (id) ); # --- !Downs DROP TABLE Post;
  • 22. 2.0 browser error reporting
  • 23. 2.0 access SQL data via Anorm import anorm._ DB.withConnection { implicit c => val selectCountries = SQL("Select * from Country") // Transform the resulting Stream[Row] to a List[(String,String)] val countries = selectCountries().map(row => row[String]("code") -> row[String]("name") ).toList } // using Parser API import anorm.SqlParser._ val count: Long = SQL("select count(*) from Country").as(scalar[Long].single) val result:List[String~Int] = { SQL("select * from Country") .as(get[String]("name")~get[Int]("population") map { case n~p => (n,p) } *) }
  • 24. 2.0 and Akka def index = Action { // using actors, coverting Akka Future to Play Promise Async { (myActor ? "hello").mapTo[String].asPromise.map { response => Ok(response) } } } def index = Action { // execute some task asynchronously Async { Akka.future { longComputation() }.map { result => Ok("Got " + result) } } } // schedule sending message 'tick' to testActor every 30 minutes Akka.system.scheduler.schedule(0 seconds, 30 minutes, testActor, "tick") // schedule a single task Akka.system.scheduler.scheduleOnce(10 seconds) { file.delete() }
  • 25. 2.0 streaming response def index = Action { val file = new java.io.File("/tmp/fileToServe.pdf") val fileContent: Enumerator[Array[Byte]] = Enumerator.fromFile(file) SimpleResult( header = ResponseHeader(200, Map(CONTENT_LENGTH -> file.length.toString)), body = fileContent ) } // Play has a helper for the above: def index = Action { Ok.sendFile(new java.io.File("/tmp/fileToServe.pdf")) }
  • 26. 2.0 chunked results def index = Action { val data = getDataStream val dataContent: Enumerator[Array[Byte]] = Enumerator.fromStream(data) ChunkedResult( header = ResponseHeader(200), chunks = dataContent ) } // Play has a helper for the ChunkedResult above: Ok.stream(dataContent)
  • 27. 2.0 Comet lazy val clock: Enumerator[String] = { val dateFormat = new SimpleDateFormat("HH mm ss") Enumerator.fromCallback { () => Promise.timeout(Some(dateFormat.format(new Date)), 100 milliseconds) } } def liveClock = Action { Ok.stream(clock &> Comet(callback = "parent.clockChanged")) } and then in template: <script type="text/javascript" charset="utf-8"> var clockChanged = function(time) { // do something } </script> <iframe id="comet" src="@routes.Application.liveClock.unique"></iframe>
  • 28. 2.0 WebSockets just another action in controller: def index = WebSocket.using[String] { request => // Log events to the console val in = Iteratee.foreach[String](println).mapDone { _ => println("Disconnected") } // Send a single 'Hello!' message val out = Enumerator("Hello!") (in, out) }
  • 29. 2.0 caching API by default uses EHCache, configurable via plugins Cache.set("item.key", connectedUser) val user: User = Cache.getOrElse[User]("item.key") { User.findById(connectedUser) } // cache HTTP response def index = Cached("homePage",600) { Action { Ok("Hello world") } }
  • 30. 2.0 i18n conf/application.conf: application.langs="en,en-US,fr" conf/messages.en: home.title=File viewer files.summary=The disk {1} contains {0} file(s). from Scala class: val title = Messages("home.title") val titleFR = Messages("home.title")(Lang(“fr")) val summary = Messages("files.summary", d.files.length, d.name) from template: <h1>@Messages("home.title")</h1>
  • 31. 2.0 testing …using specs2 by default "Computer model" should { "be retrieved by id" in { running(FakeApplication(additionalConfiguration = inMemoryDatabase())) { val Some(macintosh) = Computer.findById(21) macintosh.name must equalTo("Macintosh") macintosh.introduced must beSome.which(dateIs(_, "1984-01-24")) } } }
  • 32. 2.0 testing templates "render index template" in { val html = views.html.index("Coco") contentType(html) must equalTo("text/html") contentAsString(html) must contain("Hello Coco") }
  • 33. 2.0 testing controllers "respond to the index Action" in { val result = controllers.Application.index("Bob")(FakeRequest()) status(result) must equalTo(OK) contentType(result) must beSome("text/html") charset(result) must beSome("utf-8") contentAsString(result) must contain("Hello Bob") }
  • 34. 2.0 testing routes "respond to the index Action" in { val Some(result) = routeAndCall(FakeRequest(GET, "/Bob")) status(result) must equalTo(OK) contentType(result) must beSome("text/html") charset(result) must beSome("utf-8") contentAsString(result) must contain("Hello Bob") }
  • 35. 2.0 testing server "run in a server" in { running(TestServer(3333)) { await( WS.url("http://localhost:3333").get ).status must equalTo(OK) } }
  • 36. 2.0 testing with browser …using Selenium WebDriver with FluentLenium "run in a browser" in { running(TestServer(3333), HTMLUNIT) { browser => browser.goTo("http://localhost:3333") browser.$("#title").getTexts().get(0) must equalTo("Hello Guest") browser.$("a").click() browser.url must equalTo("http://localhost:3333/Coco") browser.$("#title").getTexts().get(0) must equalTo("Hello Coco") } }
  • 37. 2.0 Demo
  • 38. 2.0 Resources http://www.playframework.org/ https://github.com/playframework/Play20/wiki http://www.parleys.com/#st=5&id=3143&sl=4 http://www.parleys.com/#st=5&id=3144&sl=13 http://www.parleys.com/#id=3081&st=5 http://vimeo.com/41094673
  • 39. 2.0 Questions ?