This post was posted by Shaw on the ScalaCool team blog.

In the Play! In Framework Series 1, we got a first look at Play! All kinds of features and advantages, so from now on we will officially contact Play! . This article introduces Play! And then a very simple example to illustrate the relationship between the various structures and how to take advantage of Play! Agreed structures to properly organize our business logic.

An overview of structure


Image of play


The image above is based on Play! To create a simple Web application, in the last article we talked about Play! It’s an “ROR” style frame, and we can also see Play! Is a typical MVC architecture framework, in addition to Play! Also using “convention by configuration”, we can easily implement a Web application by organizing our code according to its convention structure, so let’s look at Play! The features and functions of each structure in the bar.

Business description

We’ll get to know Play by implementing a small app! It will be a little clearer. Requirement Description:

  • Implement a simple company employee information list.

As you can see, the Web application we are going to implement is very simple, so let’s Play with this little requirement! .

app

Molecular imp imp imp imp imp imp impCopy the code

The directory APP is at the top of the structure chart, and because it’s alphabetized, it should be at the top. Of course, it is also very important in our entire Play app, almost all of our business code is contained under this directory, and since it is so important, it is not unreasonable to be at the top of the list. There are three subdirectories under app: Controllers, Models, and Views.

We can also add some directories to the app directory. For example, we need to use Play! Filter (described below), we can add a new filters directory to manage the business logic of filters. Such as:

App ├ controllers ├ models ├ views ├ filtersCopy the code

Next, we’ll detail the three core structures in this directory: Controllers, Models, and Views.

models

In Web applications with MVC structure, M corresponds to Model. Under Models, we implement some logic of data access. Generally speaking, a table in the database corresponds to a Model class. Such as:

We are going to display the “employees” list. Here we need the “employees table” in the database, so under Models we create a Model that represents the employee information:

case class Employee (
  id: Long,
  name: String,
  sex: String,
  position: String
)Copy the code

In general, we also need to implement the logic to manipulate the database under the Models, but when the business is more complex, the entire file looks very messy and difficult to maintain later, so here we introduce Services, we will implement all the logic to deal with the database under the Services. Under Models, we just need it to define the corresponding Model class.

App └ controllers └ models └ views └ servicesCopy the code

services

We will create a new EmployeeService under “Services” to query employee information:

Note: this article does not involve the database, so we write all the data here, the database connection will be explained in detail in the following article.

class EmployeeService {

  val jilen = Employee(
    id = 1,
    name = "Jilen",
    sex = "Male",
    position = "All Dry Engineer"
  )

  val yison = Employee(
    id = 2,
    name = "Yison",
    sex = "Female",
    position = "Programmer motivator"
  )

  def getEmployees: Seq[Employee] = Seq(jilen, yison)
}Copy the code

views

View corresponds to V in the MVC structure. Under this structure, we implement the View in the program, that is, use Play! In view, we usually only do data rendering, and rarely implement complex logic. To render the list of employees, we create a file named Employeelist.scala.html under views. In this file, we render the data.


@(employees: Seq[Employee])

<table class="employee-list"Number > < tr > < th > < / th > < th > name < / th > < th > gender < / th > < th > job < / th > < / tr >@for(e <- employees){
    <tr>
      <td>@e.id</td>
      <td>@e.name</td>
      <td>@e.sex</td>
      <td>@e.position</td>
    </tr>
  }
</table>Copy the code

controllers

Now that we have created the Model, servic, and View, how do we render the data from the Model and Service into the view? This is where we need controllers, which correspond to C in MVC, and below controllers, we need to implement a list of actions that tie together the data of the entire Web application. To associate the previously created Model, Service, and View, we create an EmployeeController under controllers:


class EmployeeController @Inject() (
  cc: ControllerComponents
) extends AbstractController(cc) {

  val employeeSerivce = new EmployeeSerivce

  def employeeList = Action { implicit request: Request[AnyContent] = >val employees = employeeSerivce.getEmployees()
    Ok(views.html.employeeList(employees))
  }
}Copy the code

The “Action” in Play is actually a “trait”. The above code implements an “Action”, which actually uses an object Action. The “apply” method in “Object Action” then returns an Action:


// Apply method for object Action

final def apply(block: ⇒ Result) :Action[AnyContent]Copy the code

conf

Conf imp. Conf impCopy the code

Under conf, we mainly place the configuration files and routing files for the entire project.

application.conf

This file will configure Play! The secret key, database information, etc. Since our application is relatively simple, we do not need to configure this parameter. In a later article, we will focus on how to manage application.conf.

routes

We have implemented model, Service, Controller and View, so how can we access our application through the browser? We need to use “routes”, all the routes of the application will be implemented in routes, these routes are the entry point of the application. Such as:

To access the “employee list” we implemented earlier, we need to specify the corresponding route in routes:


GET    /employee/employee-list    controllers.EmployeeController.employeeListCopy the code

Specify good routing later, when we enter http://localhost:9000/employee/employee-list in your browser, can access to the “employee list” page.


Image of employee-list


In the route file, we just wrote a section to specify routes. After compiling, we can see a file named route. scala under target/scala-2.12/routes/main/router/. At the end of the file you can see:


def routes: PartialFunction[RequestHeader.Handler] = {

    case controllers_EmployeeController_employeeList0_route(params) =>
      call {
        controllers_EmployeeController_employeeList0_invoker.call(EmployeeController_0.employeeList)
      }
  }Copy the code

Routes in play! It is a “partial function” that calls the corresponding method when a request is matched. If no match is found, an error is reported. So we can also implement a route ourselves without playing! This way, of course, play! It’s much clearer and simpler to agree.

After introducing Routes, it’s important to know that when we type a link into the browser, play! How is called between each module of, as shown below:


Image of play-mvc


When we access a link, the link is a route that matches an Action in a Controller. The Action then calls methods in its dependent Service that fetch data and pass it to the Action. The Action then sends the data to the View, and the View will render the page we need. The flow is shown in the solid line, and the Controller will depend on the Model, and sometimes the View will depend on the Model and Service.

build.sbt

This file is used to define the basic information of our project and some dependencies required by the project, such as the project name, organization, version information, scala version, and some dependency definitions, etc. In our application, build. SBT can be defined as follows:


name := "HelloWorld"
organization := "com.shawdubie"

version := "1.0 the SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.12.2"

libraryDependencies += guice
libraryDependencies += "org.scalatestplus.play"% %"scalatestplus-play" % "3.1.0" % TestCopy the code

The build. SBT file is read when the SBT starts, and the SBT loads the information we define in it, such as the dependencies we declare. Build.sbt can contain a lot of information, but we’ll talk about it in more detail later.

project

Project └ build.properties └ plugins.sbtCopy the code

This directory mainly stores files after the SBT build. Before the BUILD, there are generally only two files listed above in this directory.

build.properties

The version information of the SBT that the project depends on is defined here. For example, the version of the SBT in the project can be declared as follows:

SBT. Version = 0.13.15Copy the code

plugins.sbt

In this file we declare the plugins that the project depends on. For example, we use the Play SBT plugin:

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.3")Copy the code

conclusion

This article gives an overview of Play! There are a few things that we will cover in detail in a later article. It’s just a matter of knowing. See the source link for examples in this article