Play framework is a Java web application framework based on the Model-View-Controller (MVC) architecture. Play’s lightweight, stateless, web-friendly architecture uses Akka and Akka Streams under the covers to provide predictable and minimal resource consumption (CPU, memory, threads). Thanks to its reactive model, applications scale naturally–both horizontally and vertically. Play includes all the components needed to build Web Applications and REST services, such as an integrated HTTP server, form handling, Cross-Site Request Forgery (CSRF) protection, a powerful routing mechanism, I18n support, and more.
Currently, the Play framework supports Java 11 only.
Some of the key features of the Play framework are:
- Hot reloading: Changes to the code are immediately reflected in the browser, allowing developers to see the changes in real-time.
- Scala and Java support: Play supports both the Java and Scala programming languages, making it a versatile framework.
- Lightweight: Play is designed to be lightweight, making it easy to deploy and scale.
- RESTful: Play is designed to be RESTful, making it easy to build APIs and integrate with other services.
- Asynchronous: Play is designed to be asynchronous, making it highly scalable and efficient.
- Testing support: Play has built-in support for testing, making it easy to write and run automated tests.
The Play framework follows the Model-View-Controller (MVC) architecture, which separates the application into three main components:
- Model: The model represents the data and business logic of the application.
- View: The view represents the user interface of the application.
- Controller: The controller handles user input and interacts with the model and view to process requests and generate responses.
The Play framework uses a routing mechanism to map URLs to controllers and actions. This routing mechanism is based on the HTTP method, URL path, and request parameters.
- Download SBT (Simple Built Tool).
- To create a new project.
-
Navigate to the directory and use this command.
sbt new playframework/play-java-seed.g8
Specify project and package name when prompted.
-
To run use this command.
sbt run
-
Note → For IntelliJ do not add play configuration. Run it from the in-built sbt shell.
- app → This directory contains the main source code of your Play application.
- controllers → This directory contains the controllers that handle HTTP requests and define the application's behavior.
- models → This directory is used to define the application's data models and business logic.
- views → This directory contains the view templates used to generate HTML or other types of responses.
- assets → This directory is used to store static assets such as stylesheets, JavaScript files, images, etc.
- conf → This directory contains the configuration files for your application.
- application.conf → This file contains the main configuration for your application, including settings related to database connections, logging, etc.
- routes → This file defines the URL routes and maps them to the appropriate controllers and actions.
- logback.xml → This optional configuration file, is used to configure the logging behavior of your application. It is based on the Logback framework and allows you to specify log levels, appenders, formatters, and other logging-related settings.
- public → This directory is used to store publicly accessible static files such as images, stylesheets, JavaScript files, etc. These files are served directly by the web server.
- test → This directory contains the tests for your application. It is typically organized in a structure similar to the
app
directory, with corresponding packages and subdirectories. - project → This directory contains the build-related files and plugins used by the build tool (such as sbt or Maven).
- target → This directory is automatically generated by the build tool and contains the compiled code, packaged application, and other build artifacts.
- build.sbt → This file defines the build configuration for your Play application. It uses the sbt DSL (Domain Specific Language) to specify various settings and dependencies. Some common configurations you may find in
build.sbt
include →- **
name
**→ Specifies the name of your project. - **
version
**→ Specifies the version of your project. - **
scalaVersion
**→ Specifies the version of Scala used in your project. - **
libraryDependencies
**→ Defines the dependencies of your project. You can specify Play Framework dependencies, database connectors, logging libraries, and other libraries required by your application.
- **
- plugins.sbt → This file, located in the
project
directory, is used to manage sbt plugins for your Play application. It allows you to add additional functionality to your build process. For example, you can use plugins for code quality checks, database migrations, asset compilation, and more. Plugin dependencies are specified in this file.
Plugin → A plugin in Play Framework is a module or extension that provides additional functionality to your application. It is designed to integrate seamlessly with the framework and can be used to enhance various aspects of your project. Plugins can add features such as authentication, database connectivity, caching, logging, or even custom functionality specific to your application's requirements. Play Framework provides a plugin architecture that allows you to easily add and configure plugins in your project.
Adding plugin to project →
-
Add plugin to
plugins.sbt
.addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "6.0.0")
-
Enable the added plugin in
build.sbt
.lazy val root = (project in file(".")).enablePlugins(PlayJava, PlayEbean)
A project named "root" using the
lazy val
keyword. The project is configured to be located in the current directory (file(".")
). Additionally, two plugins are enabled for this project:PlayJava
andPlayEbean
.
Dependency → In a Play Framework project, a dependency refers to an external library or module that your application relies on. Dependencies are typically third-party libraries or frameworks that provide specific functionality that you want to leverage in your project. These dependencies are not part of the Play Framework itself but can be included in your project using a build tool like sbt (Simple Build Tool) or Maven.
Adding a dependency to project →
libraryDependencies ++= Seq(
"org.projectlombok" % "lombok" % "1.18.26", //Added Dependency
guice
)
-
Define the route of the API in
routes.conf
file.GET /home/:fName/:lName controllers.BasicController.homepage(fName: String, lName: String)
-
Write a Controller class which will extend
Controller
fromplay.mvc
package. Each method corresponds to an API endpoint or a view defined in the routes file.-
basic API endpoint.
import play.mvc.Controller; import play.mvc.Result; public class BasicController extends Controller { public Result homepage(String fName, String lName) { return ok("Welcome Home! \n User -> " + fName + " " + lName); } }
-
Play template view.
-
Create a view template → Create a view template file with the
.scala.html
extension in theviews
package or directory. Let's assume we have a file named ithomepage.scala.html
.@(fName: String, lName: String) <!DOCTYPE html> <html> <head> <title>Basic View</title> </head> <body> <h1>Hello, @fName @lName!</h1> </body> </html>
Here the view expects these variables
fName
andlName
of type string. -
Render the view from a controller → In a controller method, you can pass the required data to the view by using the
ok()
method and the<viewName>.render(<parameters>)
function. The view needs to be imported manually with.html
in between the views and the package the view resides as shown below.// A view needs to be imported manually import views.html.homepage; public class BasicController extends Controller { public Result homepage(String fName, String lName) { return ok(homepage.render(fName, lName)); //Here the homepage is the name of the view } }
-
-
The Result
class represents the HTTP response sent back to the client. It encapsulates the response status, headers, and body.
You can use methods like ok()
, status()
, and withHeader()
to customize the response. The ok()
method creates a 200 OK
response without a body. The status()
method sets a specific status code for the response. The withHeader()
method adds headers to the response. You can use withJson()
to set the response body as JSON content. The as()
method sets the content type of the response.
Return a Result
object from your controller methods to send the HTTP response.
Play templates are used for generating dynamic content in Play Framework applications. They are written in a combination of HTML and a templating language (such as Twirl). Play templates allow you to embed Scala or Java code directly within the HTML markup.
You can use template tags, expressions, and control structures to create dynamic content. Templates support data binding, allowing you to pass variables and objects from your controller to the template. Templates provide a way to modularize your views and reuse common components.
They support template inheritance, allowing you to create base templates and extend them in child templates. Play templates are compiled at build time, providing better performance and error checking. You can use template helpers and utility functions to simplify common tasks, such as form rendering or date formatting.
Templates can be rendered from your controller methods and returned as responses to client requests.
<!DOCTYPE html>
<html>
<head>
<title>Play Template Example</title>
</head>
<body>
<h1>Welcome to Play Template Example</h1>
@for(i <- 1 to 5) {
<p>Number: @i</p>
}
</body>
</html>
Ebean is an Object-Relational Mapping (ORM) framework that is tightly integrated with the Play Framework, a popular web application framework for Java and Scala. It serves as the default ORM in Play Framework, providing seamless database access and persistence capabilities. Here's an explanation of Ebean in the context of the Play Framework:
- Default ORM: Play Framework incorporates Ebean as its default ORM solution. It simplifies the process of persisting and retrieving data from a relational database within your Play application.
- Configuration: Play Framework automatically configures Ebean based on the settings in the application configuration files. The configuration includes database connection details, schema generation options, and other Ebean-specific settings.
- Entity Models: In Play Framework, you define entity models using Java or Scala classes. These models represent database tables and are annotated with Ebean annotations (such as
@Entity
,@Id
,@Column
, etc.) to specify the mapping between the models and database tables. - Database Migration: Ebean in Play Framework supports automatic database schema generation and migration. It can create database tables based on your entity models and apply incremental changes to the schema as your models evolve. This simplifies the management of database schema changes during development and deployment.
- Eager Loading and Lazy Loading: Ebean provides support for both eager loading and lazy loading of related entities. With eager loading, you can fetch related entities along with the main entity in a single query, reducing database round-trips. On the other hand, lazy loading allows you to load related entities only when accessed, improving performance by fetching only the necessary data.
- Query Language: Ebean includes its own query language called Ebean Query Language (EQL). It offers a type-safe and fluent API for building queries, allowing you to express complex database queries in a concise and readable manner.
- Transaction Management: Ebean handles database transactions in Play Framework applications. It provides APIs to begin, commit, and rollback transactions, ensuring data consistency and integrity during database operations.
- Integration with Play APIs: Ebean seamlessly integrates with other components and APIs in the Play Framework ecosystem. It works well with Play's built-in JSON support, form handling, validation, and other features, making it easy to work with data in a Play application.
The Finder
class in Ebean is used for querying and retrieving data from a relational database in Play Framework. It simplifies database operations by providing methods for querying based on conditions, primary keys, and executing complex queries.
-
Adding Finder Object.
@Entity public class User extends Model { @Id private Long id; private String name; private String email; public static final Finder<Long, User> find = new Finder<>(User.class); }
Declare a static
Finder
objectfind
of typeFinder<Long, User>
associated with theUser
entity class. -
Using finder.
User user = User.find.byId(1L); //With the `Finder` object, we can execute queries. For example, the above code retrieves a `User` instance by its primary key (`id`) using the `byId()` method. List<User> users = User.find.query().where().like("name", "%John%").findList(); //The above code executes a query to find all User instances whose name contains "John" using the Finder object's query builder methods.
The Finder
class automatically generates SQL queries based on the entity class and the specified conditions.
-
Add postgres JDBC dependency
libraryDependencies += "org.postgresql" % "postgresql" % "42.5.4"
-
Configure database connection
db.default.driver = "org.postgresql.Driver" db.default.url = "jdbc:postgresql://localhost:5432/mydatabase" db.default.username = *your_username* db.default.password = *your_password*
-
Java Code
public Result getAllEmployee() { List<Employee> employeeList = Employee.employeeFinder.all(); return ok(Json.toJson(employeeList)); } public Result saveEmployee(Http.Request request) { Employee employee = Json.fromJson(request.body().asJson(), Employee.class); employee.save(); return ok("Employee saved"); } public Result getEmployeeById(Long id) { return ok(Json.toJson(Employee.employeeFinder.ref(id))); } public Result updateEmployee(Http.Request request) { Employee employee = Json.fromJson(request.body().asJson(), Employee.class); Employee existingEmployee = Employee.employeeFinder.ref(employee.getId()); existingEmployee.setDesignation(employee.getDesignation()); existingEmployee.setFullName(employee.getFullName()); existingEmployee.update(); return ok("Employee updated"); } public Result deleteEmployee(Long id) { Employee existingEmployee = Employee.employeeFinder.ref(id); existingEmployee.delete(); return ok("Employee deleted"); }
-
Specifying routing
GET /employee/all controllers.BasicController.getAllEmployee POST /employee/save controllers.BasicController.saveEmployee(request :Request) GET /employee/:id controllers.BasicController.getEmployeeById(id: Long) PUT /employee/update controllers.BasicController.updateEmployee(request :Request) DELETE /employee/:id controllers.BasicController.deleteEmployee(id: Long)