Creating Web Applications with Play! – An introduction

Play! is an open-source framework for building web applications in Java or Scala. It is stateless and promotes RESTfulness: it embraces web-oriented architecture. But best of all, Play is simple, fast and ultimately fun. It is also pretty powerful and allows the development of sophisticated web applications in an efficient way. akquinet is now using Play as the basis for different applications.

To illustrate how easy and powerful Play is, this blog post presents a miniature web application.

It’s a basic library interface, where books may be checked out and returned at the press of a button. Then, the page reloads and the updated availability status is shown.

The following is just a small sample of what Play can do. Play is a sophisticated framework with many other features that we don’t have room to represent here (such as excellent support for testing, the ability to configure dynamic routing to create clean, RESTful URLs, and access to a wide variety of modules such as user authentication), but the intention of this post is simply to show how Play can enable you to build powerful web applications quickly and easily.

The finished source code for the project can be found on GitHub.

Initialization

First, download Play! and install it according to the instructions. (It shouldn’t take more than five minutes.)

We create a new Play! project via the command line:

play new Play--Framework-Example--Library

After entering the project’s name when prompted, the project is created. At this point, the application can already be run with play run Play--Framework-Example--Library. It can be viewed at http://localhost:9000 but at this stage will only show Play’s default welcome message.

While it’s not necessary to use a full-featured IDE to develop with Play (since it takes care of the compilation and deployment itself), it can be more convenient. Happily, Play provides us with a couple of IDE-specific commands to simplify the process of importing the project into such an IDE, e.g.

play eclipsify Play--Framework-Example--Library

With the correct Eclipse configuration files in place, we can import the project into Eclipse as an existing Java project, and begin editing.

Editing a Play application is a surprisingly pleasant experience. This is largely because it does not require recompilation or redeploying/restarting every time changes are made in code or templates. The effects of changes may be seen just by hitting “refresh” in the web browser, saving considerable amounts of time and removing a source of much frustration.

The project is structured so that in addition to the app folder where the Java source lives, there are folders for web resources (images, JavaScript and stylesheets), configuration files and external modules and libraries, among others. The structure of the application itself is strictly divided into models, views and controllers.

Structure of a Play! application

Before getting on with the application, we’re going to add some CSS to the stylesheet. A main.css file is included by default in the stylesheets folder, and is referenced from the master view, app/views/main.html. There is nothing special in here. The resulting CSS is here.

Creating entities

Play provides JPA support. The first thing we will do for our application is define a Book model. As this is a very simple application, all our Book needs is a title, author and an isCheckedOut flag. We will import Play’s JPA Model class, and Book will extend this in order to take advantage of some standard JPA methods such as findAll(). It will also create an id for each book.

We mark Book as an entity, and use Play’s validation library to assert that title and author are both required. This will take care of bean validation and later, if we need it, HTML form validation. We will also add a method to check books out, which will simply update the isCheckedOut flag and persist the changes before returning. (The Play team’s decision in favor of explicit save is described here)

Note that when building models with Play, all properties should be declared public. It is something to get used to, but this way Play will generate the getters and setters and take care of the encapsulation for us.

package models;

import javax.persistence.Entity;

import play.data.validation.Required;
import play.db.jpa.Model;

@Entity
public class Book extends Model {

    @Required
    public String title;

    @Required
    public String author;

    public boolean isCheckedOut = false;

    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    public Book checkOut() {
        isCheckedOut = true;
        this.save();
        return this;
    }
}

Creating a view

Next, we will update the application’s start page. We will display a title and a simple table showing the title, author and availability. The default landing page is app/views/Application/index.html, which extends our master main.html view.

Play’s templating is based on the Groovy language. There are some standard tags available, and you can also write your own. One of Play’s own tags, #{welcome}, is responsible for displaying the default welcome message. We will replace that tag with our title and table, using the #{list items: books, as: 'book'} syntax to do the repetition required to generate the rows of books, and standard Groovy syntax to access each book’s properties. For now we will leave out the “borrow” button, and just concentrate on displaying the book’s properties.

#{extends 'main.html' /}
#{set title:'Library' /}</pre>
<div id="header">
<h1>Our Library</h1>
</div>
<div id="main">#{list items:books, as:'book' } #{/list}
<table id="books">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>${book.title}</td>
<td>${book.author}</td>
<td>${book.isCheckedOut ? 'Checked Out' : 'Available'}</td>
<td></td>
</tr>
</tbody>
</table>
</div>
<pre>

At this point, refreshing the index page won’t show us our table, it will display an error message. Thankfully, Play has excellent error messages, so the problem is clear: we can’t display books because we don’t even have a database!

Database not configured

Even better, Play gives us an easy way to address our problem by creating a temporary database while we are developing. We’ll take a look in the conf folder, and make a change to application.conf. We will scroll down to the “Database configuration” section and uncomment the line db=mem to enable an in-memory H2 database.

# Database configuration
# ~~~~~
# Enable a database engine if needed.
#
# To quickly set up a development database, use either:
#   - mem : for a transient in memory database (H2 in memory)
#   - fs  : for a simple file written database (H2 file stored)
db=mem

Now, when we refresh the page, we can see our page at last.

The main view of our application

Adding data at startup

The table is currently empty, because although we now have a database, we still don’t have any books in it. But how to get books in there? Do we have to build an interface to add them? No, Play also provides us with a way to load up temporary data at runtime. We’ll first create a Bootstrap class, which inherits from Play’s Job class. We’ll annotate it with @OnApplicationStart, and tell it that if there are no Books in the database at that time, to load up data from a YAML file that we specify.

import play.*;
import play.jobs.*;
import play.test.*;

import models.*;

@OnApplicationStart
public class Bootstrap extends Job {

    public void doJob() {
        // Check if the database is empty
        if (Book.count() == 0) {
            Fixtures.loadModels("initial-data.yml");
        }
    }
}

The YAML format provides a straightforward way to quickly define some test data, e.g.

Book(Android):
    title: Android Application Development
    author: Rick Rogers, John Lombardo, Zigurd Mednieks and Blake Meike

Book(JavaScript):
    title: JavaScript Patterns
    author: Stoyan Stefanov

With a database and test data configured, we can now restart the application (for the first time since we started editing!) to load up the test data. However, refreshing the index page does not show any changes. That’s because we haven’t yet configured our controller to find the book details and pass them to the view.

Loading and injecting entities

Let’s take a look at app/controllers/Application.java. Application is the default controller for our application. It currently contains one method, known as an action method: public static void index(). The method name is mapped to the view for the appropriate controller, i.e., our start page at app/views/Application/index.html. The call to render() can contain arguments to be passed to our view.

Our view is expecting a list of Books. Since we want to display all books in our database, and our Book class extends Model, we can use the JPA method Book.findAll() to find and return all our books. So, we can update our index action method as follows.

    public static void index() {
        List books = Book.findAll();
        render(books);
    }

And finally, refresh our index page once more to see the list of books displayed in the table.

Our library with books

Implementing actions

Now that we have our books displaying in our table at last, we want to be able to check them out. Let’s create another method for that in our controller.

    public static void borrowBook(Long bookId) {
        Book book = Book.findById(bookId);
        book.checkOut();
        index();
    }

Here we will again take advantage of Book‘s inheriting from Model, as we will find and identify the book to check out based on its id. Then, we will call checkOut() on the book, and finally call index() to refresh the page and reveal the change in status.

We can now go back to the index page and add in the Borrow button to the table’s fourth column:

    #{if !book.isCheckedOut}
    #{form @Application.borrowBook(book.id)}<input type="submit" value="Borrow" />#{/form}
    #{/if}

The #{form} tag is a very nice shortcut to writing a full HTML form tag. All that is required to define is the form’s action. We define that as the borrowBook method in the Application controller, and pass in the ID of the book as the argument. The only input required is the submit button. As easily as that, we can refresh the index page once more and try out our Borrow button.

The library view with the check out button
The library now displaying the book’s updated status

It works! However, we have room for a little improvement tweak. At the moment we are not giving the viewer a lot of visual feedback on the change. But Play allows us to pass messages between actions using what it terms the flash scope. We can update our borrowBook method to add a success message:

    public static void borrowBook(Long bookId) {
        Book book = Book.findById(bookId);
        book.checkOut();
        flash.success("You have checked out %s", book.title);
        index();
    }

Before we can see the message, we need to make room for it in our view.

  #{if flash.success}
    ${flash.success}
  #{/if}

And now, if we check out the second book, we will get a nice status message confirming the change.

Displaying a ‘flash’

Adding a second action

If you download the finished source code from GitHub, you will see that we have added a second action to be able to return books. However, we won’t go into the details here, as the action is just the reverse of “borrow”.

Using the CRUD module to manage entities

We can use the optional CRUD module to provide interfaces for administering our entities. The CRUD module comes with Play, so we don’t need to download it, just add it to our list of dependencies.

Edit /conf/dependencies.yml to add the line
- play -> crud
below the line
- play

Then, do:

play dependencies
play eclipsify

to update Play with the change and to add CRUD to the build path.

CRUD comes with some default routes. We import these into /conf/routes by adding the line

/admin              module:crud

Finally, restart Play for the changes to take effect.

With the CRUD module installed, we need to create a new controller for our Book entity that extends CRUD, i.e.

package controllers;

import play.*;
import play.mvc.*;

public class Books extends CRUD {
}

With that, we can view our admin interface at http://localhost:9000/admin and follow through to the books interface.

To get nicer identifiers for each book, add a toString() method to the Book entity:

public String toString() {
     return title + " - " + author;
}

To preserve the changes between restarts, edit the db= line in /conf/application.conf to change from db=mem to db=fs, and restart.

The CRUD Module in action

Conclusion

We hope this little demonstration has shown how simple it is to use Play to build powerful web applications. Play is an innovative web framework allowing the implementation of sophisticated applications in a rapid manner. akquinet is now using Play! for several projects.