×

Don't miss out

Subscribe to our free newsletter for user guides, tips & tricks, technology news, security alerts and special offers. We promise not to spam you.

Subscribed. Thank you!

Build your first Play Framework web application

by Kennedy • 26th November 2015 Add a comment

main story image

In this article, I will show you how to build your first Play Framework web application. We will be building a CRUD app (Create, Read, Update and Delete) together with Play framework (2.x). This guide was first used at the BT Developer Conference (BT DevCon 2015) on 27 November 2015.

 

About Play Framework

Play is based on a lightweight, stateless, web-friendly architecture. Built on Akka, Play provides predictable and minimal resource consumption (CPU, memory, threads) for highly-scalable applications. Play makes it easy to build web applications with Java & Scala based on the MVC model. The Play framework is used by many well-known organisations in the world such as LinkedIn, GOV.UK, The guardian and Ocado. You can read more about the Play Framework on their website here.

 

Play Framework introduction video (Java version)

 

What I like about Play is that:

  • It's MVC based
  • It is very easy to build web applications. I really mean it!
  • It is powerful like Ruby on Rails but in Java and Scala!
  • Scala is a very powerful functional programming language. It also challenges you to think differently. We will do some coding with this language later.
  • The play framework is definitely very reliable

Okay enough of the introduction, let's get our hands dirty and do some coding. This is what we are here for :)

 

Prerequisite

In this session, I will be using:

How to install the play framework: https://www.playframework.com/documentation/2.0/Installing

Please note Play 2.1.5 does not have the activator feature, hence the console command will be slightly different from the video above.

IDE: Play supports both Eclipse and IntelliJ (I will be using Eclipse for the demo) https://www.playframework.com/documentation/2.0/IDE

 

Since it is getting close to the Christmas holiday season, let's build a database to record the actors/actresses in a pantomime.

 

The coding exercise

Create a project

Create a new play project

play new pantomime <enter>

<enter>

Press "2" (for java project)

 

Go to the project folder

cd pantomime

 

Link it with IDE (I will be using Eclipse here)

play eclipse

 

Opening eclipse IDE

Start Eclipse

Import the project

File -> Import -> General -> Existing projects into Workspace

Browse and select the project folder e.g. pantomime

Click finish to import

 

Exploring the directories

app.controllers (location for your controllers)

app.views (location for your view templates)

            Written in scala / HTML

test (location for your test modules, a few examples have been provided)

conf (

            application.conf

            routes

public (to store your assets)

            stylesheets, images, javascripts etc...

 

Run the project

To run it at port 8080

play “~run 8080”

 

Test it

Open a browser and go to http://localhost:8080/

If it is working, you will see some Play help webpages.

 

What we are going to do next is to add a model, then add a view template and some controller functions. We are going to do the view and controller in multiple parts.

 

Model

So let's start by adding the “Actor” model.

It needs to be placed in a package called models.

 

To create the java file, right click on app, select New, Click on Other... select java class

package: models

Name: Actor

Click finish

 

In Actor.java, import these libraries

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.Id;

import play.data.validation.Constraints;

import play.db.ebean.*;

import java.util.*;

 

Actor needs to “extends Model

Add @Entity on top of the class

@Entity

public class Actor extends Model {

}

 

Add data model code

@Id

@GeneratedValue

public Long id;

 

@Constraints.Required

public String firstname;

 

@Constraints.Required

public String lastname;

 

public Integer age;

 

public String role;

 

Need to add default constructor to make it work properly.

public Actor() {

}

 

Add code to help us debug

public String toString()

{

    return "id: " + id + " firstname:" + firstname + " lastname:" + lastname + " age:" + age + " role:" + role;

}

 

 

Enable Queries

// -- Queries  

public static Model.Finder<Long,Actor> find = new Model.Finder(Long.class, Actor.class);

 

// Find by id:

public static Actor findById( Long _id )

{

           return find.where()

                                    .eq( "id", _id )

                                    .findUnique();

}

 

// Find all:

public static List<Actor> findAll() {

       return find.all();

}

 

See no need to write a single line of SQL so far!

 

Let's add the facility to create some actors (Create)

View (part 1)

Let's create an HTML form so that we can add actors

right click on views, select New, click on file

enter filename: addactorform.scala.html

 

In the file, at the top, we add the input the parameters. Let's add the following

@(theform: Form[models.Actor])(message: String)

 

Let's take a look at main.scala.html. It has most of the ingredients we need for constructing an HTML document, so let's reuse that by calling the main function.

 

@main("Add Actor"){

            <p>Hello World</p>

            <p>@message</p>

}

 

Controller (part 1)

Let's add a controller function to show the form and a controller function to process and add an Actor (create).

 

Go to controllers.Application and import these libraries:

import models.*;

import static play.data.Form.form;

import play.*;

import play.data.Form;

import play.mvc.*;

import views.html.*;

 

For showing the form, add:

public static Result showAddActorForm() {

           Form<Actor> theform = form(Actor.class).bindFromRequest();

            return ok( addactorform.render(theform,"") );

}

 

For processing the form POST, add:

public static Result addActor() {

           return ok("add actor");

}

 

 

Now go to conf -> routes

Add:

GET                 /addactor                                    controllers.Application.showAddActorForm()

POST              /addactor                                     controllers.Application.addActor()

 

 

Before we move to the second part, let's do a test

Goto: http://localhost:8080/addactor

 

View (part 2)

Go back the addactorform.scala.html, let's add a function to help us create Bootstrap style input fields

@myInputField(fieldname: String, label: String = "", placeholder: String = "" ) = {

     <div class="form-group @if(theform(fieldname).hasErrors){ has-error}">

                       <label class="col-sm-2 control-label" for="@fieldname">@label</label>

                       <div class="col-sm-6">

                                   <input class="form-control" type="text" name="@fieldname" id="@fieldname" placeholder="@placeholder" value="@theform(fieldname).value">

                                   @if(theform(fieldname).hasErrors) {

                                               <span class="help-inline">@theform(fieldname).errors.head.message</span>

                                    }

                       </div>

     </div>

}

 

Add some form code using the play framework helper:

<h1>Add Actor</h1>

@helper.form(action = routes.Application.addActor, 'id -> "addactorform", 'class -> "form-horizontal") {

                        @myInputField("firstname","Firstname","Enter firstname")

                        @myInputField("lastname","Lastname","Enter lastname")

                        @myInputField("age","Age","Enter age")

                        @myInputField("role","Role","Enter role") 

                       

                        <div class="form-group">

                                    <label class="col-sm-2 control-label"></label>

                                    <div class="col-sm-6">

                                                <button class="btn" type="submit">Submit</button>

                                    </div>

                        </div>   

}

 

Let's do another test

Goto: http://localhost:8080/addactor

 

How come there is an error “error.required” on the page? Because the form was not initialised properly. So let's go back to the controller and make the following modification:

return ok( addactorform.render(theform.fill(new Actor()),"") );

 

Let's test it again. The error is gone! Great! Let's test the form post... Any suggestions of names?

Next, let's put more code in the controller.

 

Controller (part 2)

Let's add some more code to process the POST part:

public static Result addActor() {

      Form<Actor> theform = form(Actor.class).bindFromRequest();

          

      if(theform.hasErrors()) {

           Logger.error("Error: " + theform.errorsAsJson() );               

           return badRequest( addactorform.render(theform, "Error: " + theform.errorsAsJson() ) );

       }

       else

       {    

           Actor actor = theform.get();

           actor.save();

           Logger.debug( actor.toString() );

           return ok( addactorform.render(theform,"success") );

       }

}

 

Let's do another test.

Error!!!!! [PersistenceException: The default EbeanServer has not been defined?]

What's going on? We didn't enable the ORM properly yet. We need to do that. So let's check the application.conf file

 

Unmark:

ebean.default="models.*"

 

Enable the in memory database by unmarking the db config lines too:

db.default.driver=org.h2.Driver

db.default.url="jdbc:h2:mem:play"

db.default.user=sa

db.default.password=""

 

Now let's try it again. It is asking whether we want to create the table actor. As you can see, Play is helping us to create the required table. We don't need to type in a single line of SQL. Let's click on “Apply this script now!” to continue.

 

List all the entries (READ)

Let's upgrade the current view template so that it can show the list of entries.

Add the following parameter in the template, so that we can pass the data from the controller to the template.

@(theform: Form[models.Actor])(thelist: List[models.Actor])(message: String)

 

 

List it out, add the following code in the body after the add actor code:

<h1>The list</h1>

<ul>

            @for( actor <- thelist ){

                        <li>@actor.toString()</li>

            }

</ul>

 

 

Add the additional input parameter to the controller functions (in 3 places):

, Actor.findAll()

 

Delete function (DELETE)

Let's add some code in the controller to perform the delete function.

public static Result deleteActor(Long _id) {

          Form<Actor> theform = form(Actor.class).bindFromRequest();

           Actor actor = Actor.findById(_id);

          

           if ( actor == null)

           {

                       return badRequest( addactorform.render(theform.fill(new Actor()), Actor.findAll(), "Actor not found" ) );

           }

           else

           {

                       actor.delete();

                       return ok( addactorform.render(theform.fill(new Actor()), Actor.findAll(), "Actor deleted" ) );

           }

          

   }

 

 

In the routes file add:

GET                 /deleteactor                                             controllers.Application.deleteActor( id: Long )

 

 

In the template: add the link after @actor.toString():

<li>@actor.toString()  <a href="@routes.Application.deleteActor( actor.id )">Delete</a></li>

 

Now let's test it!

 

Edit function (UPDATE)

Let's add some code in the controller to perform the edit function.

 

public static Result editActor(Long _id) {

           Form<Actor> theform = form(Actor.class).bindFromRequest();

           Actor actor = Actor.findById(_id);

          

           if ( actor == null)

           {

                       return badRequest( addactorform.render(theform.fill(new Actor()), Actor.findAll(), "Actor not found" ) );

           }

           else

           {

                       return ok( addactorform.render(theform.fill(actor), Actor.findAll(), "" ) );

           }

   }

 

 

In the routes file, add:

GET                 /editactor                                                controllers.Application.editActor( id: Long )

 

 

In the template file, after @actor.toString(), add:

<li>@actor.toString() <a href="@routes.Application.editActor( actor.id )">Edit</a> <a href="@routes.Application.deleteActor( actor.id )">Delete</a></li>

 

Now let's test it again. How come it is making duplicate? Because the controller can't tell whether it is in create mode or edit mode. Let's add a few tweaks to make it work:

 

In the view, inside the helper form, add the following. This will help us to distinguish between a new object and an old object:

<input type="hidden" name="id" value="@theform("id").value">

 

In the controller, addActor, replace/add the following code code:

Actor actor = theform.get();

 

if ( actor.id == null )

{

           // it's a new object

           actor.save();

           Logger.debug( actor.toString() );

           return ok( addactorform.render(theform, Actor.findAll(), "success") );

}

else

{

           // it's an old object

           actor.update();

           Logger.debug( actor.toString() );

           return ok( addactorform.render(theform, Actor.findAll(), "updated") );

}         

 

Add some styling

How come the form looks a bit poorly styled? Let's enable the Bootstrap styling.

 

Copy Bootstrap files

Copy the css, javascript and font files in the appropriate folders in <project folder>/public/

 

Enable Bootstrap

In the main.scala.html file, locate the header and add:

<link rel="stylesheet" href="@routes.Assets.at("stylesheets/bootstrap.min.css")" type="text/css">

 

Use real database?

Currently we are using Play in memory database. Certainly we can change the config to point to a SQL database such as MySQL.

 

Do a clean up first:

play clean-all

 

In the application.conf

# Link to my SQL database

db.default.driver=com.mysql.jdbc.Driver

db.default.url="jdbc:mysql://localhost:3306/pantomimedb?characterEncoding=UTF-8"

db.default.user="username"

db.default.pass="password"

 

In Build.scala, add the following line in the middle to import the mysql connector library. Don't forget to add a comma at the end of the previous item.

"mysql" % "mysql-connector-java" % "5.1.18"

 

Great! We have created a CRUD webapp in this session. I hope this gives you an idea of how easy it is to create a webapp with Play. I hope you like it and will continue using it!

 

Have fun!

 

I will upload a copy of the project code in the next few days.

 

In the meantime, enjoy coding. If you have any questions or comments, please feel free to contact me here or leave a comment below

 

Please leave a comment Please sign in to leave a comment
KEEP IN TOUCH...

Don't miss out on our free user guides, tips & tricks, relevant technology news, security alerts and special offers in our free newsletter

SUBSCRIBE NOW
GOT A COMPUTER PROBLEM?

Need some help with your computer?

Why not get a friendly local IT expert who can pop around and give you some help? It's simple, affordable and convenient.

We can help you with anything from providing you independent advice through setting up, fixing or upgrading your computer, to teaching you how to use your computer, on a 1-to-1 basis.

BOOK NOW
ARE YOU AN IT EXPERT?

Are you passionate about technology? Are you the one who people turn to for help? Are you interested in helping more people and get paid?

Sign up and become a lxpert.

FIND OUT MORE