Play framework
VinaSaver – Tien Nguyen
2017
Play framework - Overview
-
Play is a high-productivity Java and Scala web application framework that integrates the components and APIs you need for modern web
application development.
-
Play is based on a lightweight, stateless, web-friendly architecture and features predictable and minimal resource consumption (CPU,
memory, threads) for highly-scalable applications thanks to its reactive model, based on Akka Streams.
Play Framework
2
ADVANtages Play Framework
Like many frameworks, Play is based on the MVC model (model, view, controller).
Runs on the JVM, which has years of experience and optimizations.
It's auto compiled, so you may expect better performance.
It's really fullstack: can develop a web app, compiler, web server,….
It uses the asynchronous mechanism.
…
Play Framework
3
Play framework and laravel
Laravel
Play Framework
•
Using MVC architecture (Makes code much more manageable and easier to
navigate)
•
Using MVC architecture (Makes code much more manageable and easier to
navigate)
•
Auto-compiling (No wait time to see the changes that are made being
implemented)
•
Auto-compiling (Java doesn’t normally do this but Play has built it in)
•
•
Fullstack: can develop a web app, compiler, web server
Fullstack: can develop a web app, compiler, web server
•
•
Evolutions
Migration
•
•
Java/Scala language
PHP language
•
•
Open-source (Doesn’t seem to be quite as extensive as Laravels but still big)
Open Source (Loads of great addons and libraries to enhance the
functionality of the system without having to custom code)
Play Framework
4
Environment Setup On local server(1)
1. Create virtual host to run your app by adding following rows to file /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ProxyPreserveHost On
ServerName
www.demo-scala.com
ProxyPass
/excluded !
ProxyPass
/ http://127.0.0.1:9500/
ProxyPassReverse
/ http://127.0.0.1:9500/
</VirtualHost>
2. Install Java Software Development Kit (SDK) and set your java environment
3. Sbt
SBT is an open source build tool for Scala and Java projects, similar to Java’s Maven or Ant.
To install sbt please refer to />
Play Framework
5
Environment Setup On local server(2)
4. Typesafe-activator
Activator is build upon sbt and can do everything that sbt can do, plus more. Activator New is a fast way to create new Scala projects from a range of different templates and
start building them immediately. It replaces the Play command in Play Framework.
Install activator
Download activator: wget />And add the activator script to your PATH
Ex: export PATH=$PATH:/usr/bin/activator-1.3.12/bin/
Create new project with exsiting template play-scala with command
>activator new [project-name] play-scala
>cd [project-name]
Run project
or run with port 9500
Play Framework
>activator run
>activator “run 9500”
6
Deploy On Product Server
1. Using the dist task builds a binary version of your app that you can deploy to a server having Java installation.
>sbt dist
This produces a ZIP file containing all JAR files in target/universal folder of your app.
2. To run the app, unzip the file on target server, then run the script in the bin directory. The name of the script is your app name
>unzip demo-scala-1.0.zip
>demo-scala-1.0/bin/demo-scala –Dplay.scrypto.secret=abcdefghijk
You can also specify a different configuration file for production environment
>demo-scala-1.0/bin/demo-scala –Dconfig.file=/full/path/to/conf/application-prod.conf
Play Framework
7
Structure play framework project
Source code includes those important folders and files
1. “app” folder: All scala main code of project is put at here
2. “build.sbt” file: In this file you declare plugins library that using in project
3. “conf” folder: In this folder has 2 important files
- “application.conf”: Set config of all plugins that you declare in build.sbt
- “routes”: Define all application routes
4. “public” folder: Include using css, js, image files in project
Play Framework
8
Mvc in play framework
Play Framework
9
View (1)
Most of the application views are generated using an efficient templating system provided by play.
The Controller gets some interesting data from the model layer, and then applies a template to decorate these objects.
View are defined in the app/views folder
Following a simple naming convention (e.g. user.scala.html)
Template parameters : A template is like a function, so it needs parameters, which must be declared at the top of the template file
View can using template available.
Play Framework
10
View (2)
Example :
main.scala.html (template)
index.scala.html
<!DOCTYPE html>
@(message: String)
<html lang="en">
@* Using template views/main.scala.html *@
<head>
@main("Welcome to Play") {
@* Here's where we render the page title `String`. *@
<title>@title</title>
@message
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/template.css")">
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
}
<script src="@routes.Assets.versioned("javascripts/hello.js")"type="text/javascript"></script>
</head>
<body id="login" class="nosubnavi">
@content
</body>
</html>
index.scala.html using template main.scala.html with parameters title: String = “Welcome to Play” and content : Html = “
@message
”
Play Framework
11
Controller (1)
An action is a Java/Scala entry point invoked when a HTTP Request is received.
The action method extracts relevant data from the HTTP request, reads or updates the model objects, and
sends back a result which is wrapped into an HTTP Response.
Can return view or redirect to URI controller.
Example :
package controllers
import play.api.mvc._
class Application extends Controller{
index.scala.html
def index = Action {
@* Get parameters message from controller *@
//Return page views/index.scala.html with parameter
message : String = “Welcome Play Framework”
@(message: String) @main("Welcome to Play") {
Ok(views.html.index(“Welcome Play Framework”))
@* Using parameter message*@
@message
// Redirect(routes.UsersController.user)
}
}
}
Play Framework
12
Controller (2)
Example : Call models/Users
views/user.scala.html
package controllers
@(user:List[Users], email: String) //get data from controller
import play.api.mvc._
@main("Users",email) {
import models.Users
<table class="table table-hover">
// import model Users
<tbody>
class Application extends Controller{
@for((t,index) <- user.zipWithIndex) {
def index = Action {
<tr>
//Call function getAllUsers() in models/Users
<td>@t.name</td>
val user = Users.getAllUsers()
<td>@t.email</td>
val email = “”
//Return views/user.scala.html with data (user,
</tr>
email_user)
}
Ok(views.html.user(user,email_user))
</tbody>
}
</table>
}
}
Play Framework
13
Model
The domain model object layer is a set a Java/Scala classes using all the object oriented features available from the Java/Scala language.
It contains data structures and operations on which the application operates.
Example :
package models
import scalikejdbc._
case class Users(id: Int, name: String, email: String, password: String, api_token: String)
object Users extends SQLSyntaxSupport[Users]{
def findById(id: Int)(implicit s: DBSession = AutoSession): Option[Users] = {
sql"select id,name,email,password,api_token,created_at,updated_at from users where id = ${id}
rs.string("password"),
rs.string("api_token")) }.single.apply()
.map { rs => Users(rs.int("id"), rs.string("name"), rs.string("email"),
}
}
Play Framework
14
Routes
The router is the component in charge of translating each incoming HTTP request to an Action.
An HTTP request is seen as an event by the MVC framework. This event contains three major pieces of information:
•
The HTTP method (e.g. GET, POST,…)
•
The request path (e.g. /user/1,…)
•
The URI controller (e.g. controllers.UsersController.show(id: Int),…)
Routes are defined in the conf/routes file
Example :
GET
/login
POST /login
Play Framework
controllers.AuthenicationController.login
controllers.AuthenicationController.auth
15
action
•
Most of the requests received by a Play application are handled by an Action
•
A play.api.mvc.Action is basically a (play.api.mvc.Request => play.api.mvc.Result) function that handles a request and generates a result to be sent to the client.
Example :
def index = Action {
Ok(“It’s work!”)
}
def user = Action {
Redirect(routes.UsersController.user)
}
Play Framework
16
Database
Use the ScalikeJDBC library to connect database(MySQL)
Add the MySQL JDBC dependency to the build.sbt file
libraryDependencies ++= Seq( jdbc)
libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.24"
Configuration mysql in conf/application.conf file
db { default.driver = com.mysql.jdbc.Driver
default.url = "jdbc:mysql://localhost/tien_scala“
default.username = root
default.password = "vinasaver“
}
Install ScalikeJDBC to run query, add to build.sbt
libraryDependencies ++= Seq(
"org.scalikejdbc" %% "scalikejdbc" % "2.4.1",
"org.scalikejdbc" %% "scalikejdbc-config" % "2.4.1",
"org.scalikejdbc" %% "scalikejdbc-play-initializer" % "2.5.1")
Play Framework
17
evolutions
Evolutions is used to create relational databases for easy tracking and organization.
CREATE TABLE users (
Add evolutions into your dependencies list (in build.sbt):
libraryDependencies += evolutions
# --- !Ups
Create evolutions script: The first script is named “1.sql”, the second script “2.sql”,
and so on… and should be located in “conf/evolutions/default”
If you agree with the SQL script, you can apply it directly by clicking on the ‘Apply
evolutions’ button.
id int(10) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
email varchar(255) NOT NULL,
password varchar(255) NOT NULL,
api_token varchar(60) NOT NULL,
created_at timestamp,
updated_at timestamp,
PRIMARY KEY (id)
);
Play Framework
18
REST API(1)
Method : GET
Step 1: Add url routes
GET
/all controllers.UsersController.all()
Step 2: Create function all()
def all() = Action { implicit request =>
implicit val userFormat = Json.format[Users]
val list_user = Users.getAllUsers()
Ok(Json.obj("success"-> true,
"data" -> list_user,
"error" -> ""
)
)
}
Play Framework
17
REST API(2)
Method : POST
Step 1: Add url routes
POST
/test controllers.UsersController.test()
Step 2: Create function test()
def test() = Action.async(parse.urlFormEncoded) { implicit request =>
implicit val userFormat = Json.format[Users]
val email = request.body("email").head
val password = request.body("password").head
val list_user = Users.authenication(email,password)
Future(Ok(Json.obj("success"-> true,
"error" -> ""
)
"data" -> list_user,
)
)
}
Play Framework
18
Demo App(1)
Step 1: Set application routes
In conf/routes set routes like
GET
/login
controllers.AuthenicationController.login
POST /login
controllers.AuthenicationController.auth
GET
/logout
controllers.AuthenicationController.logout
GET
/
controllers.UsersController.index
GET
/user
controllers.UsersController.user
GET
/edit/:id
controllers.UsersController.editpage(id: Int)
POST /edit/:id
controllers.UsersController.edit(id: Int)
GET
controllers.UsersController.addpage()
/add
POST /add
GET
/delete/:id
controllers.UsersController.add()
controllers.UsersController.delete(id: Int) After that run command line
> activator run
To see how does it look like.
For more functionalities in this app please refer to source code.
Play Framework
21
Demo App(2)
Create screen login (login.scala.html)
@(message:String)
@page("Login page") {
<div id="dMain" class="">
<div class="article" id="aMainContents">
<div id="dMainColumn">
<div class="dLogOut">@message</div>
<form name="login" action="@routes.AuthenicationController.auth" method="post">
<label for="email">ID</label>
<input maxlength="100" id="email" class="fWideM" name="email" type="text" value="">
<label for="password"> パパパパパ </label>
<input maxlength="100" id="password" class="fWideM" name="password" type="password" value="">
<input class="btnImg" value=" パパパパ " alt=" パパパパ " id="submit" name="sbm_cnf" type="submit">
<div class="dMessage">
<div class="dModBoxPadding02 dModBoxBorderNightBlue">
パパパパパパ
<ul class="ulModEleAttention lastElement">
<li>※ パパパパパパパパパパパパパパパパパパパパパパパパパ
パパパパパパパパパパパパパパパパパパパパパパパパパパパパ
</li>
<li>※ パパパパパパパパパパパパパパパパパパパパパパ </li>
<li>※ パパパパパパパパパパパパパパパパパパパパ
パパパパパパパパパパパパパパパパパパパパパパパパパパパパパパ
</li>
</ul>
</div>
</div>
</form>
</div>
</div>
</div>
}
Play Framework
22
Demo App(3)
Create Model Users (function authentication, updateApiToken)
case class Users(id: Int, name: String, email: String, password: String, api_token: String)
object Users extends SQLSyntaxSupport[Users]{
def md5(s: String) = {
MessageDigest.getInstance("MD5").digest(s.getBytes).map("%02x".format(_)).mkString
}
def authenication(email: String, password: String)(implicit s: DBSession = AutoSession): Option[Users] = {
sql"select id,name,email,password,api_token,created_at,updated_at from users where email = ${email} and password = ${md5(password)}"
.map { rs => Users(rs.int("id"),rs.string("name"),rs.string("email"),rs.string("password"),rs.string("api_token")) }.single.apply()
}
def updateApiToken(id: Int)(implicit s: DBSession = AutoSession):Boolean = {
val api_token:String = System.currentTimeMillis().toString()
val result_query = withSQL { update(Users).set(Users.column.api_token -> md5(api_token)).where.eq(Users.column.id, id) }.update.apply()
if(result_query > 0) return true
else return false
}
}
Play Framework
23
Demo App(4)
Create AuthenicationController
class AuthenicationController extends Controller {
def loginForm = Form(mapping("email" -> text, "password" -> text)
(LoginRequest.apply)(LoginRequest.unapply))
case class LoginRequest(email:String, password:String)
def login() = Action { request =>
val api_token = request.session.get("api_token").getOrElse("")
val id_user = request.session.get("user_id").getOrElse("0")
if (api_token.isEmpty || id_user.isEmpty){
Ok(views.html.login(""))
}else{
val info_user = Users.checkLogin(id_user.toInt,api_token)
if(info_user != None){
Redirect(routes.UsersController.user)
}else{
Ok(views.html.login(""))
}
}
}
def auth = Action { implicit request =>
val loginRequest = loginForm.bindFromRequest.get;
handleRespone(loginRequest)
}
def handleRespone(request: LoginRequest): Result = {
val result = Users.authenication(request.email,request.password)
Framework
if(result != Play
None){
val update_token = Users.updateApiToken(result.get.id.toInt)
24
Demo App(5)
Screen Login : Login success -> List Users
Play Framework
25