Hello, Play!
No introductory technical article would be complete without the classic “Hello, World” example, so let’s go ahead and build a “Hello, Play” example.
Execute play new HelloPlay to create a new play application:
Stevens-MacBook-Pro:Workspace shaines$ play new HelloPlay _ _ __ | | __ _ _ _ | '_ \| |/ _' | || | | __/|_|\____|\__ / |_| |__/ play 2.2.2 built with Scala 2.10.3 (running Java 1.7.0_25), http://www.playframework.com The new application will be created in /Users/shaines/Documents/Workspace/HelloPlay What is the application name? [HelloPlay] > Which template do you want to use for this new application? 1 - Create a simple Scala application 2 - Create a simple Java application > 2 OK, application HelloPlay is created. Have fun! Stevens-MacBook-Pro:~ shaines$
When creating a new play application, you can choose to create a Java or a Scala application. Here we’ll stick to Java, but if you’re a Scala fan, you are free to create a Scala Play application as well.
The wizard creates the following artifacts for you:
README README file to be included with your application app Application sources controllers Your application controllers (the C in MVC) views Your application views (the V in MVC) – template files (models) Your application model classes (the M in MVC) (assets) Assets to be bundled with your application (typically need to be compiled) (stylesheets) CSS files (LESS files) for your application (javascripts) JavaScript/CoffeeScript files for your application build.sbt Main build file for your application conf Configuration files application.conf Main configuration file for your application routes Routes file, which is used for mapping URIs to actions project SBT configuration files build.properties Marker file for the SBT build tool plugins.sbt SBT plug-in list public Public assets images Application images stylesheets Application CSS files javascripts Application JavaScript files test Source folder for unit tests
Play uses the Simple Build Tool (SBT) to build your application, so you’ll see a lot of “sbt” artifacts throughout the project. Your main application source code can be found under the “app” folder, which defines the following default directories:
- controllers: Play uses the Model-View-Controller (MVC) design pattern, and this directory contains your controllers. Controllers define an action method that Play maps to a URI using the conf/routes file.
- views: Views are implemented using a special template language called Scala templates. Don’t worry; you do not need to learn Scala. Scala templates are a lot like JSP files, but the markup in the files follow Scala constructs: Just think of these files as another templating language.
- models: Although this directory is not created for you by the wizard, it is where you will define your model classes. Note that Play applications tend to be domain-driven, so your model classes will have both data as well as persistence methods. This is a departure from Spring-like applications that define model objects as containing only data and persistence is delegated to a repository class, but if you follow the convention, then it will all make sense.
- assets: Although this directory is not created for you, it is meant to contain your application assets and most typically assets that need to be compiled. You should store LESS files to be compiled to CSS files and CoffeeScript files to be compiled to JavaScript files in these directories. Assets that are already compiled, such as CSS and JavaScript files, and raw assets, such as images, should be stored in the “public” folder.
We’ll look at the other application resources as we need them. Let’s run our application and see what it does. Execute the “play” command from the “HelloScala” directory. You should output similar to the following:
Stevens-MacBook-Pro:HelloPlay shaines$ play Getting org.scala-sbt sbt 0.13.0 ... :: retrieving :: org.scala-sbt#boot-app confs: [default] 43 artifacts copied, 0 already retrieved (12440kB/1006ms) [info] Loading project definition from /Users/shaines/Documents/Workspace/HelloPlay/project [info] Set current project to HelloPlay (in build file:/Users/shaines/Documents/Workspace/HelloPlay/) _ _ __ | | __ _ _ _ | '_ \| |/ _' | || | | __/|_|\____|\__ / |_| |__/ play 2.2.2 built with Scala 2.10.3 (running Java 1.7.0_25), http://www.playframework.com > Type "help play" or "license" for more information. > Type "exit" or use Ctrl+D to leave this console. [HelloPlay] $
This leaves you in the Play console where you can manage your Play application. You can run the application by executing the run command:
[HelloPlay] $ run [info] Updating {file:/Users/shaines/Documents/Workspace/HelloPlay/}helloplay... [info] Resolving org.fusesource.jansi#jansi;1.4 ... [info] Done updating. --- (Running the application from SBT, auto-reloading is enabled) --- [info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000 (Server started, use Ctrl+D to stop and go back to the console...)
Your Play application is now running and listening on port 9000. You can access it through the following URL:
http://localhost:9000
You should see a screen similar to Figure 1.
Figure 1 New Play Application Homepage
When you open http://localhost:9000, your browser executes an HTTP GET command for the “/” resource. Play’s conf/routes file maps the URI request for GET / to the action method defined in the controllers directory, Application class, index() method. Listing 1 shows the source code for the Application class.
Listing 1. Application.java
package controllers; import play.*; import play.mvc.*; import views.html.*; public class Application extends Controller { public static Result index() { return ok(index.render("Your new application is ready.")); } }
The Application class is a controller because it extends Play’s play.mvc.Controller base class; you can browse the Play JavaDoc here. The Controller class defines a collection of helper methods, such as the ok() method (via its play.mvc.Results super class) that tells Play to return an HTTP 200 – OK response.
The index() method is referred to as an “action method” because HTTP requests are routed to “actions” for processing. All action methods are static and act as singletons – part of Play’s model is to ensure that all action methods are thread safe and should not manage state in the controller class.
There is a little Play magic going on in the index() method that I’d like to explore. When Play builds your application, it generates Scala source files from the view templates (app/views) to the following directory:
/target/scala-2.10/src_managed/main/views
And then it compiles those Scala source files to the following directory:
/target/scala-2.10/classes/views/html
Finally, this classes directory is added to your CLASSPATH so that when we import views.html.* we can access our compiled view templates. Putting this all together, a new Scala source file (target/scala-2.10/src_managed/main/views/html/index.template.scala) is created from the app/views/index.scala.html file, is compiled to a Java class (target/scala-2.10/classes/views/html/index.class), and that class is added to your CLASSPATH.
When you see index.render(“…”) it means that Play is executing the render() method, which accepts a String, on the index class. If Scala doesn’t scare you, take a look at the generated source file, find the render() method, and see what it’s doing:
/target/scala-2.10/src_managed/main/views/html/index.template.scala
The render() method returns a Scala object that implements the play.mvc.Content interface that contains the rendered HTML template. The rendered HTML is then passed to the ok() method, which wraps the HTML with an HTTP 200 response. Play then sends the final response back to the client.
Figure 2 shows a sequence diagram that summarizes this interaction.
Figure 2 Handling a Web Request Using a Scala Template
With that background out of the way, let’s update our Hello, Play application to return “Hello, Play” instead of showing the default application page. Modify the Application class’s index() method to what is shown in Listing 2.
Listing 2. Application.java (Updated for Hello, Play Message)
package controllers; import play.*; import play.mvc.*; import views.html.*; public class Application extends Controller { public static Result index() { //return ok(index.render("Your new application is ready.")); return ok( "Hello, Play!" ); } }
Now, instead of rendering a template, we simply return the text “Hello, Play!” wrapped in an HTTP 200 OK response. Save your file and go ahead and reload the page. (Note that you do not need to rebuild anything; Play will find the changed file and recompile the file for you.) Instead of seeing the rendered template, you should simply see the text “Hello, Play!”
Now let’s add a query parameter with the name of the person to greet. Listing 3 shows another version of the index() method that accepts a name String.
Listing 3. Application.java (Updated for Hello, your name Message)
package controllers; import play.*; import play.mvc.*; import views.html.*; public class Application extends Controller { public static Result index( String name ) { //return ok(index.render("Your new application is ready.")); return ok( "Hello, " + name + "!" ); } }
But for this to work, we need to update the routes file to tell Play that we expect a name parameter to be passed by the caller. Listing 4 shows our updated routes file.
Listing 4. conf/routes
# Routes # This file defines all application routes (Higher priority routes first) # ~~~~ # Home page # GET / controllers.Application.index() GET / controllers.Application.index(name:String) # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.at(path="/public", file)
The original routes file mapped an HTTP GET for the resource “/” to controllers.Application.index() but now we have augmented it to accept a name query parameter that is of type String. The syntax is different from Java: You specify the parameter name, followed by a colon and then the type of the parameter. In this example this is: “name:String”. Save the routes file and then reopen your browser to http://localhost:9000. You should see an error message stating that a name parameter is required and not provided! Now add a name parameter, as follows:
http://localhost:9000?name=YourName
Now you should see a response of “Hello, YourName”.
Before we close out this section, let’s build a simple Scala template HTML file and use it to render our Hello, Play text. First, let’s add a new action method to the Application class named hello(). Listing 5 shows the new contents of the Application.java file.
Listing 5. Application.java (New hello() method)
package controllers; import play.*; import play.mvc.*; import views.html.*; public class Application extends Controller { public static Result index( String name ) { //return ok(index.render("Your new application is ready.")); return ok( "Hello, " + name + "!" ); } public static Result hello( String name ) { return ok( hello.render( name ) ); } }
The new hello() method invokes the views.html.hello class’s render method to generate HTML, which means we are going to have to create a new file in the apps/views folder named hello.scala.html. Listing 6 shows the contents of this Scala template.
Listing 6. hello.scala.html
@(name:String) <!doctype html> <html> <head> <title>Hello, Play</title> </head> <body> <h2>Hello, @name!</h2> </body> </html>
The hello.scala.html template defines a required parameter at the beginning of the file:
@(name:String)
The format is the same as defined in the routes file. This line requires a String parameter to be passed to the template’s render() method and then that value will be available through the name variable. Later in the template we obtain the value of the name variable by using the @name notation. We’ll review more details on Scala templates in the next article.
Finally we need to update the routes file, which is shown in Listing 7.
Listing 7. conf/routes (with New /hello URI)
# Routes # This file defines all application routes (Higher priority routes first) # ~~~~ # Home page # GET / controllers.Application.index() GET / controllers.Application.index(name:String) GET /hello controllers.Application.hello(name:String) # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.at(path="/public", file)
The new route maps GET /hello to the Application class’s hello() method. Save all three files and then load the new hello action with the following URL:
http://localhost:9000/hello?name=YourName
You should see the following output:
<!doctype html> <html> <head> <title>Hello, Play</title> </head> <body> <h2>Hello, YourName!</h2> </body> </html>
As you can see, the name parameter was substituted for YourName.
Summary
The Play Framework is not a traditional Java web framework and actually requires us to think about developing web applications differently. It runs in its own JVM, not inside a Servlet container, and it supports instant redeployment of applications without a build cycle. When building Play applications you are required to think in terms of HTTP and not in terms of Java.
This article presented an overview of Play, showed how to set up a Play environment, and then built a Hello, World application. In the next article we’ll look at building more complicated web applications, explore the Scala template language, and see how Play uses domain-driven objects. In the final article we’ll integrate Play with Akka to realize the true power of asynchronous messaging and see how to suspend a request while waiting for a response so that we can support more simultaneous requests than a traditional Java web application.