Sie sind auf Seite 1von 7

BROUGHT TO YOU IN PARTNERSHIP WITH

202
GETTING STARTED WITH CONTENTS

Play Framework 


Introduction to Play Framework

Create a New Play App

Routing Requests

A Web Framework for Java and Scala  Controllers

 Server-Side Templates

UPDATED BY MARCOS PEREIRA - ORIGINAL BY RYAN KNIGHT

INTRODUCTION TO PLAY FRAMEWORK DIRECTORY DESCRIPTION


The Play Framework is a high velocity web framework for Java and test The test source directory.
Scala that enables a highly productive workflow but doesn’t sacrifice
scalability. Play features a “just-hit-refresh” workflow that enables a project sbt configuration files.
rapid development cycle. The compilation and application reloading
happens behind the scenes. Play is built for the modern web by being You can have both Java and Scala sources for your backend code.
non-blocking, RESTful by default, and having built-in asset compilers However, Play has an idiomatic Java API and a separate idiomatic Scala
for modern client-side technologies like TypeScript, CoffeeScript, API because the idioms differ between the two languages. This creates
LESS, and more. an experience that “feels right” with whatever language you use. The
packages in Play for Scala begin with play.api while the Java API lives
CREATE A NEW PLAY APP under the Play package prefix.
The easiest way to get started with Play is with Lightbend Starter
ROUTING REQUESTS
Projects - a place where you can download sample projects that contains
all that you need to get started: The conf/routes file defines how Play routes requests based on
their HTTP verb and path. When you make a request to http://
1. Go to: developer.lightbend.com/start/?group=play.
localhost:9000 your browser makes a GET request with a / path. You
2. Download one of the sample projects.
can see in the default routes file there is a routing definition to handle
3. Unzip it and run “./sbt run” command in your terminal.
that case:
Your new Play application should be running and you should be able to
GET / controllers.HomeController.index()
browse to localhost:9000 and see your new application.
The third parameter is the method (the action) that will be responsible
To get to the local documentation for Play, navigate to
for handling the request and returning a response. The structure of the
localhost:9000/@documentation.
routes file is
Another way to create a new app is by using the sbt new command. You VERB PATH CONTROLLER_CLASS.CONTROLLER_METHOD
will need sbt 0.13.15 or newer. To create a new project using “sbt new,”
you can run the following command: Only valid HTTP methods are allowed. If you change GET to FOO, you
will get a compile error indicating that FOO is not a valid method.
sbt new playframework/play-java-seed.g8

Or, for a new Scala project: v


sbt new playframework/play-scala-seed.g8 How The Internals Of Play
After that, you can either use a basic code editor or import your project
in IntelliJ or Eclipse by using ScalaIDE.
Framework Make Your Web
Your new project has the following layout:
Apps (And Team) Super-Fast
DIRECTORY DESCRIPTION

app
The app source directory for Java, Scala, and client
side source code.
GET THE PDF
The config directory containing the route mapping,
conf
application configuration, and log configuration.

The static assets directory (e.g. images, HTML, CSS,


public
JavaScript).

DZONE.COM | © DZONE, INC. VISIT DZONE.COM/REFCARDZ FOR MORE!


Deep Dive for Architects and Developers

How The Internals Of Play


Framework Make Your Web Apps
(And Team) Super-Fast

TECHNICAL WHITE PAPER

PLAY FRAMEWORK: THE


JVM ARCHITECT’S PATH TO
SUPER-FAST WEB APPS
THE POWER OF A STATELESS, STREAMING,
REACTIVE WEB FRAMEWORK

By Will Sargent | Lightbend, Inc.

UPGRADE YOUR GRAY MATTER


3 GETTING STARTED WITH PLAY FRAMEWORK

The path part of the routes file can be parameterized to extract package controllers
information and pass it to the controller. For instance, to pull an id out of a
path, you would do this: import javax.inject.Inject

import play.api.mvc.BaseController
GET /user/:id controllers.Users.get(id: Long)
import play.api.mvc.ControllerComponents

The “:” matches on one / separated segment, allowing you to extract class FooController @Inject()(val controllerComponents:
ControllerComponents) extends BaseController {
multiple values like:
def get = Action {
GET /user/:id/:name controllers.Users.get(id: Long, name:
Ok(“Hello foo”)
String)
}
}
You can also extract the rest of the path using a “*” like this:
The primary difference with this Scala example is that the controller
GET /files/*file controllers.Files.get(file: String)
returns an Action which holds a function that takes a request (optionally
specified) and returns a response. Just as the Java controller, by default,
Paths can also use regex expressions to limit what they match on.
we use dependency injection to create an instance of the controller.
Query string parameters can be automatically extracted into controller It can be provided by Guice or it can use compile-time Dependency
method parameters. To handle a GET request to /foo?bar=neat, define a Injection. The controllerComponents instance injected has a number of
route like this: built-in utilities so that we can have simpler controllers, but as long as
you have an Action, it will work.
GET /foo controllers.FooController.get(bar: String)

The Controller class (in the Java API) has some convenience methods to
The query string parameters are type-safe, so if you set the type as Int, interact with the other parts of the request and response:
then there will be an error if the parameter cannot be converted to an Int.
METHOD DESCRIPTION
You can also have default and optional parameters.
Returns the HTTP context, which can be used
ctx() to retrieve and store data relevant to the
One of the reasons that Play compiles the routes file is to provide a
current request.
reverse routing API so that you never have to hard code URLs into your
application. Instead, you call a method in the reverse router, which returns
Can be used to access a state that is only
the route defined by the “routes” file. This enables you to easily refactor flash(), flash(String
available for a single request after the current
your URLs without breaking your app. key), and flash(String
one (this is useful for displaying messages
key, String value)
after a redirect).
CONTROLLERS
session(),
Controllers in Play are responsible for handling a request and returning session(String key), Can be used to access the session state which
a response. Here is a basic Java controller (which would live in app/ session(String key, is backed by a cookie.
controllers/FooController.java): String value)

package controllers;
Return the current HTTP request object,
import play.mvc.Result; which can be used for reading HTTP request
request()
import play.mvc.Controller; headers, body, and any other data related to
the request.
public class FooController extends Controller {

public Result get() { Returns the current HTTP response object,


return ok(“Hello Foo”); response() which can be used to set cookies, HTTP
} headers, etc.
}

By extending the base play.mvc.Controller class, we pull in some


In the Scala API, these types of operations are done either on the Action
convenience methods, but doing so is not required. The controller
function’s optional request parameter or on the Result, for example:
instance is created by using Guice, a dependency injection framework.
The get() method returns a play.mvc.Result, which represents the HTTP
def get = Action { request =>
response. In this case, the response is a status code “200 OK” response
because the ok helper was used to set that status code. There are many Ok(“Hello”)
.withHeaders(“Foo” -> “bar”)
other helpers like notFound and badRequest that wrap the general
.withSession(“SessionFoo” -> “The-value”)
purpose play.mvc.Status API. The response body in this example is just a }
String, but it could also be HTML content, a stream, a file, etc.
There are other response helper methods that you can use depending on
The corresponding Scala controller is quite similar (and would live in app/
the HTTP Status code you need to be returned:
controllers/FooController.scala):

DZONE.COM | © DZONE, INC. BROUGHT TO YOU IN PARTNERSHIP WITH


4 GETTING STARTED WITH PLAY FRAMEWORK

are also numerous other plugins that support a large variety of other
HTTP STATUS JAVA SCALA
templating systems. To use the Scala templates, create a something.scala.
200 OK OK OK html file in the app/views directory. The naming of the file is used to
name the function that will be called to render the template:
201 Created created() Created

301 Moved PATH BECOMES


movedPermanently MovedPermanently
Permanently
app/views/foo.scala.html views.html.foo()
302 Found found Found
app/views/users/show.scala.html views.html.users.show()
303 See Other seeOther or redirect SeeOther
To use the compiled template from Java, simply call the render
307 Temporary static method:
temporaryRedirect TemporaryRedirect
Redirect
views.html.foo.render()
308 Permanent
permanentRedirect PermanentRedirect
Redirect
From Scala, use the apply function:
404 Not Found notFound NotFound
views.html.foo()

406 Not Acceptable notAcceptable NotAcceptable Templates can take parameters, so the (optional) first line of a Scala
template is the parameters. Every Scala statement in a Scala template
415 Unsupported
unsupportedMediaType UnsupportedMediaType is prefixed with an @, so to specify that a template takes a String
Media Type
parameter, use the following:
500 Internal Server
internalServerError InternalServerError
Error
@(message: String)
Any status status(413, “Oops”) Status(413)(“Oops”)
The body of the template is just a combination of “@” prefixed Scala
Controllers in Play are internally asynchronous and non-blocking, and statements and raw HTML. For instance:
there is support for using non-blocking APIs in a more idiomatic way. For
@(title: String, message: String)
example, you can just return a Result directly, as shown before, or your
actions can return CompletableFuture<Result>:
<html>
<head>
public CompletableFuture<Result> getAsync() { <title>@title</title>
// Some async API call </head>
CompletableFuture<String> asyncApiResponse = <body>
someAsyncApi(); <h1>@message</h1>
return asyncApiResponse </body>
.thenApply(value -> ok(“Api Result: “ + value)); </html>
}
Since the Scala templates are compiled into functions, they are easily
composed. If the previous example is named main.scala.html, then to
In Scala, there is Action.async to better integrate with APIs returning
reuse it from within another template, simply do this:
a Future:
@main(“My Page Title”, “Some message”)
def getAsync = Action.async {
val asyncApiResponse: Future[String] = someAsyncApi()
asyncApiResponse.map(value => Ok(“Api Result: “ + value)) Typical template operations like loops just use normal Scala expressions,
} like so:

Interceptors can be added to controllers in order to add security, logging, @for(name <- names) {
<li>@name</li>
caching, and other custom behaviors. This is called Action Composition. }
In Play’s Java API, annotations are used to add the interceptors. In Scala,
Action Composition is achieved through functional composition. A conditional “if” statement would look like:

Controllers go much deeper than the typical request and response @if(names.isEmpty()) {
<h1>Nothing to display</h1>
handling. For instance, a controller can return a stream or it can be
} else {
used to setup a push connection (Comet, EvzentSource, WebSocket, <h1>@{names.size()} names!</h1>
etc). Controllers can also handle more than just HTML; they can be used }

for JSON, binary files, or any content type using custom Body Parsers.
The Scala templates include a number of other features and patterns,
like reusable HTML components, including forms via the @form function.
SERVER-SIDE TEMPLATES One of the huge benefits of the Scala templates is that you will see
Web applications can use server-side templates as a way to create HTML compile errors in your browser just like you do with controllers, routes,
content. In Play, the default server-side templating system is Twirl. There and everything else that is compiled by Play.

DZONE.COM | © DZONE, INC. BROUGHT TO YOU IN PARTNERSHIP WITH


5 GETTING STARTED WITH PLAY FRAMEWORK

JSON These examples show serializing and de-serializing an object. Both the
Java and Scala APIs in Play have methods for traversing a JSON structure
In addition to regular HTML content, Play controllers can also receive to locate and extract data, as well as methods to create and manipulate
and return JSON serialized data. The Play Java API wraps the popular JSON structures.
Jackson library with some convenience functions. Here is an example
Java controller that has actions to get a User from somewhere (a To set up routing to either of these controller methods, add the following
database, for example) and transform it to JSON, and another action to to your routes file:
receive a JSON, parse it to a User object, and save it. Let’s first assume
GET /users/:id controllers.UsersController.get(id:
that we have the following model:
Long)
package models; POST /users controllers.UsersControllers.save

public class User {


public String name;
public String email; STATIC ASSETS
}
The public directory contains static assets that do not need to go
And then the controller: through a compilation process to be used in the browser. There is a
default mapping in the conf/routes file that sets up a way to serve these
package controllers;
assets from the /assets/ URL prefix using Play’s built-in Assets controller:
import models.User;
import play.libs.Json; GET /assets/*file controllers.Assets.at(path=”public”, file)
import play.mvc.Result;
import play.mvc.Controller;
At first glance, it seems that these assets are being read directly out of
import com.fasterxml.jackson.databind.JsonNode;
the file system. However, doing so would make Play applications
public class UsersController extends Controller {
more difficult to deploy since Play uses a container-less deployment
public Result get(Long id) { model that is ultimately just a bunch of jar files. Instead, Play’s built-in
User user = getUserFromSomewhere(id);
return ok(Json.toJson(user)); Assets controller serves assets from within the Java classpath. The
} public directory is actually a source directory that puts its contents
public Result save() { into a public package in the classpath (or generated jar file when
JsonNode json = request().body().asJson();
creating a distribution).
User user = Json.fromJson(json, User.class);

saveUserSomehow(user); To load an asset via a server-side template, use the reverse router to get
return created(“User was created”); the right URL, like so:
}
}
<img src=”@routes.Assets.at(“images/favicon.png”)” >

The same thing in Scala works in a similar way, but uses a macro-based Given the previous routing definition, the reverse router will resolve that
API to generate the serializer and de-serializer at compile time, thus to the /assets/images/favicon.png path.
avoiding the use of runtime reflection. Again, let’s first create a
model class: pa
ASSET COMPILER
package models Play has an Asset Compiler built-in that will compile client-side assets
case class User(name: String, email: String) like CoffeeScript and LESS as part of the normal compilation process.
This process will also minify JavaScript resources to reduce their size.
And the controller: Assets to be compiled go in either the app/assets/javascripts or app/
assets/stylesheets directory. For example, a new app/assets/javascripts/
package controllers
index.coffee file will be compiled and added to the classpath as assets/
import models._ javascripts/index.js and minified as assets/stylesheets/index.min.js. To
import play.api.mvc._
import play.api.libs.json.Json load the minified JavaScript via a server-side template, use

class UsersController(val controllerComponents: <script src=“@routes.Assets.versioned(“javascripts/index.


ControllerComponents) extends BaseController { js”)”></script>

implicit val userFormat = Json.format[User]


For production distributions, Play will also do JavaScript concatenation.
def get(id: Long) = Action { There are a number of other open source asset compiler plugins for Play.
val user: User = getUserFromSomewhere(id)
Ok(Json.toJson(user))
Check out the sbt-web plugins list.
}

def save = Action(parse.json) { request => TESTING


val user = request.body.as[User]
The test directory contains the unit, functional, and integration tests
saveUser(user) for your project. You can write your tests with any framework that
Created(“User was created”) has a JUnit compatible test runner. Play has some specific helpers for
} JUnit, Specs2 (a Scala testing framework) and ScalaTest (another Scala
}

DZONE.COM | © DZONE, INC. BROUGHT TO YOU IN PARTNERSHIP WITH


6 GETTING STARTED WITH PLAY FRAMEWORK

testing framework). You can test different parts of a Play application To read that config in Java, you need to inject a Config object:
independently without starting a server, or your tests can also start a
import javax.inject.Inject;
Play server, make actual requests against the server, and test the UI with
Selenium through a fake browser (HTMLUnit) or through a real browser import com.typesafe.config.Config;
(Chrome, Firefox, etc). Here is a simple Java and JUnit test of a controller:
public class FooReader {
package controllers;
private final Config config;
import org.junit.Test;
import play.Application; @Inject
import play.inject.guice.GuiceApplicationBuilder; public FooReader(Config config) {
import play.mvc.Http; this.config = config;
import play.mvc.Result; }
import play.test.WithApplication;
public String getFoo() {
import static org.junit.Assert.assertEquals; return this.config.getString(“foo”);
import static play.mvc.Http.Status.OK; }
import static play.test.Helpers.GET; }
import static play.test.Helpers.route;

public class HomeControllerTest extends WithApplication { In Scala, things are similar, except you need to inject play.api.
@Test Configuration instead:
public void testIndex() {
Http.RequestBuilder request = new Http.RequestBuilder() import javax.inject.Inject
.method(GET)
import play.api.Configuration
.uri(“/”);

// app variable is provided by WithApplication. class FooReeader @Inject()(config: Configuration) {


Result result = route(app, request); def foo = config.get[String](“foo”)
assertEquals(OK, result.status()); }
}

} You can specify additional config files to deal with configuration that
varies between environments. Play’s config system is built on the
The same thing with Scala and ScalaTest would be Typesafe Config library. See more about how Play uses it here.

package controllers
BUILD
import org.scalatestplus.play._ Play uses the sbt build tool for managing dependencies, compiling the
import org.scalatestplus.play.guice._ app, running the app, running the tests, and packaging the app. The
import play.api.test._
import play.api.test.Helpers._
project/build.properties file specifies the version of sbt to use. Any sbt
plugins can be added in the project/plugins.sbt file. The primary build
class HomeControllerSpec extends PlaySpec with
definition is in the build.sbt file, which will look something like this:
GuiceOneAppPerTest {

“HomeController GET” should { name := “your-project-name”


organization := “com.acme”
“render the index page from the router” in { version := “1.0-SNAPSHOT”
val request = FakeRequest(GET, “/”) lazy val root = (project in file(“.”)).enablePlugins(PlayJava)
val home = route(app, request).get scalaVersion := “2.12.3”
libraryDependencies += guice
status(home) mustBe OK
contentType(home) mustBe Some(“text/html”)
contentAsString(home) must include (“Welcome to Play”) Note: For Scala projects, make sure to use PlayScala instead of PlayJava
} when enabling plugins. This changes some defaults in Play’s template
} compiler to make it more idiomatic Scala.
}
The libraryDependencies section of the build.sbt defines the application
You can run the tests either using your IDE or from the command line dependencies that should be available in a public Maven repository.
using sbt test. See more about how to run tests with sbt here. You can also add your own Maven repository using the resolvers setting.
The dependencies in libraryDependencies are a comma-separated list
in this form:
CONFIGURATION
The conf/application.conf file contains your application’s default libraryDependencies += “group” % “artifact” % “version”
configuration. There, you can override config or define your own. For
instance, if you want to create a new config parameter named “foo” with As an example, to add the MySQL driver, add the following line:
a value of bar, you would simply add the following to the file:
libraryDependencies += “mysql” % “mysql-connector-java” %
foo = bar “6.0.6”

DZONE.COM | © DZONE, INC. BROUGHT TO YOU IN PARTNERSHIP WITH


7 GETTING STARTED WITH PLAY FRAMEWORK

Play has a number of optional dependencies with shortcut aliases: • Lightbend Project Starter contains a number of other templates
that will get you started learning about other aspects of Play
DEPENDENCY JAVA SCALA developers.lightbend.com/start/?group=play

JDBC Connection Pool and APIs jdbc javaJdbc • Creating a REST API with Play
github.com/playframework/play-scala-rest-api-example (see github.
com/playframework/play-java-rest-api-example for Java)
ehcache (or ehcache (or
Cache API
cacheApi) cacheApi)
• Play and JPA
github.com/playframework/play-java-jpa-example
Built-in Filters (gzip, etc) filters filters
• Official and third-party tutorials
playframework.com/documentation/2.6.x/Tutorials
Guice APIs and Dependencies guice guide

There are numerous modules for Play like:


Play WS ws javaWs
• Deadbolt 2 - an authorization system for Play 2
github.com/schaloner/deadbolt-2
Play’s build also supports sub-projects so that you can partition your
application into multiple smaller pieces. This can improve build times and • Email Plugin
make different pieces more easily reusable. github.com/playframework/play-mailer

• Check out the full Play modules list


FURTHER LEARNING
playframework.com/documentation/latest/ModuleDirectory
• Lightbend provides a free online Play training course:
lightbend.com/services/training

ABOUT THE AUTHOR

MARCOS PEREIRA I’m an experienced developer and product manager based in Rio de Janeiro, Brazil. Over
my career, I have worked as a developer, and also as a manager with a focus on how software can transform
business. I first started contributing to Play around December of 2014, and have been one of our most
active contributors since then. Regarding Play, I have been involved in many discussions, code reviews, and
improvements to the code and documentation. Also, I took an active role in helping out the Play community
through the Play mailing list and public forums, like StackOverflow. Since December of 2016, I’m now working
for Lightbend as one of the core developers for PlayFramework.

BROUGHT TO YOU IN PARTNERSHIP WITH

DZone communities deliver over 6 million pages each month to more than
3.3 million software developers, architects and decision makers. DZone offers
something for everyone, including news, tutorials, cheat sheets, research
guides, feature articles, source code and more.

DZONE, INC. REFCARDZ FEEDBACK


"DZone is a developer's dream," says PC Magazine. 150 PRESTON EXECUTIVE DR. WELCOME
refcardz@dzone.com
CARY, NC 27513
SPONSORSHIP
Copyright © 2017 DZone, Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval
888.678.0399 OPPORTUNITIES
system, or transmitted, in any form or by means electronic, mechanical, photocopying, or otherwise, without prior
919.678.0300 sales@dzone.com
written permission of the publisher.

Das könnte Ihnen auch gefallen