Après avoir lu un certain nombre de tutoriaux sur Scala, Play et MongoDB (ici, ici, ici…) et regardé pas mal de projets sur github, je me suis rendu compte qu’ils étaient tous vieux et ne correspondaient plus aux versions actuelles. Voici donc, encore un autre tutoriel sur ces technologies mais avec des versions actualisées. Nous voici donc partis avec :

  • Scala 2.10.2
  • Play 2.2.1
  • MongoDB 2.4.8
  • Salat 1.4.0

Le but de cet article va être de construire une application simple. Si vous ne n’avez pas déjà tout installé, c’est le moment de le faire : install MongoDB, install Play, install Scala.

Première étape : Créer notre application Play

play new playScalaMongoSample

Create play app

Pour démarrer notre application, il suffit alors d’aller dans le dossier de l’application et de lancer le serveur : cd playScalaMongoSample/ puis play pour accéder à la console sbt et enfin de lancer le serveur avec la commande run.

Create play app

Bravo ! Votre application fonctionne !!! Maintenant, rendez-vous sur votre application : localhost:9000. Vous devriez voir la page d’accueil de Play :

Create play app

Deuxième étape : Ajouter la dépendance sur MongoDB

Créez un fichier Build.scala dans le dossier project/ et ajoutez-y les dépendances de salat :

import sbt._
import Keys._
import play.Project._
 
object ApplicationBuild extends Build {
  val appName = "playScalaMongoSample"
  val appVersion = "1.0-SNAPSHOT"
 
  val main = play.Project(appName, appVersion).settings(
    libraryDependencies ++= Seq("se.radley" %% "play-plugins-salat" % "1.4.0"),
    routesImport += "se.radley.plugin.salat.Binders._",
    templatesImport += "org.bson.types.ObjectId")
}

Créez ensuite le fichier play.plugins dans le dossier conf/ et déclarez le plugin salat :

500:se.radley.plugin.salat.SalatPlugin

Dans le fichier conf/application.conf, ajoutez les lignes suivantes :

dbplugin=disabled
evolutionplugin=disabled
ehcacheplugin=disabled
mongodb.default.db="crud"

Le paramètre mongodb.default.db détermine le nom de la base qui sera utilisée dans MongoDB.

Troisième étape : Ajoutez les routes de l’application

Pour cela on va mettre un place un simple CRUD (Create Read Update Delete) basé sur MongoDB.

Pour cela commençons par créer les différentes routes qui seront utilisées. Ajoutez les lignes suivantes au fichier conf/routes :

# CRUD Users
GET    /users                       controllers.CRUDApp.users
POST   /users                       controllers.CRUDApp.newUser
POST   /users/:username/delete      controllers.CRUDApp.deleteUser(username: String)

Quatrième étape : Créez vos modèles

Pour fonctionner et se connecter à la base de données, salat à besoin d’un contexte (MongoContext.scala) que nous allons créer dans le dossier app/models :

package models
 
import com.novus.salat._
import play.api.Play.current
import play.api.Play
 
package object MongoContext {
  implicit val context = {
    val context = new Context {
      val name = "global"
      override val typeHintStrategy = StringTypeHintStrategy(when = TypeHintFrequency.WhenNecessary, typeHint = "_t")
    }
    context.registerGlobalKeyOverride(remapThis = "id", toThisInstead = "_id")
    context.registerClassLoader(Play.classloader)
    context
  }
}

On peut maintenant créer notre classe User qui sera manipulée par notre CRUD. Pour que salat puisse bien mapper notre classe, il faut impérativement que ce soit une case class. Voici notre User :

package models
 
import play.api.Play.current
import java.util.Date
import com.novus.salat._
import com.novus.salat.annotations._
import com.novus.salat.dao._
import com.mongodb.casbah.Imports._
import se.radley.plugin.salat._
import MongoContext._
 
case class User(username: String)
 
object User extends ModelCompanion[User, ObjectId] {
  val dao = new SalatDAO[User, ObjectId](collection = mongoCollection("users")) {}
 
  def all(): List[User] = dao.find(MongoDBObject.empty).toList
  def create(username: String) {
    dao.insert(User(username = username))
  }
 
  def delete(username: String) {
    dao.remove(MongoDBObject("username" -> username))
  }
  def findOneByUsername(username: String): Option[User] = dao.findOne(MongoDBObject("username" -> username))
}

Cinquième étape : Codez le contrôleur

On peut maintenant commencer à coder le contrôleur CRUDApp qui va effectuer l’ensemble des actions prévues :

package controllers
 
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import models._
 
object CRUDApp extends Controller {
  val userForm = Form(
    "username" -> nonEmptyText)
 
  def users = Action {
    Ok(views.html.CRUD(User.all(), userForm))
  }
 
  def newUser = Action { implicit request =>
    userForm.bindFromRequest.fold(
      errors => BadRequest(views.html.CRUD(User.all(), errors)),
      username => {
        User.create(username)
        Redirect(routes.CRUDApp.users)
      })
  }
 
  def deleteUser(username: String) = Action {
    User.delete(username)
    Redirect(routes.CRUDApp.users)
  }
 
}

Sixième étape : Ajoutez l’interface

Maintenant que la logique est terminée, il faut tout simplement ajouter l’interface graphique. Pour cela, il nous faudra simplement créer CRUD.scala.html dans le dossier app/views/ :

@(users: List[User], userForm: Form[String])
 
@import helper._
@main("User CRUD - Play starter") {
    <div class="container">
 
      <h1>@users.size user(s)</h1>
      <ul>
      @users.map { user =>
          <li>
              @user.username
              @form(routes.CRUDApp.deleteUser(user.username)) {
                  <input type="submit" value="Delete">
              }
          </li>
      }
      </ul>
 
      <h2>Add a new User</h2>
      @form(routes.CRUDApp.newUser) {
          @inputText(userForm("username"))
          <input type="submit" value="Create">
      }
 
    </div> <!-- /container -->
}

Votre application est maintenant prête !!!

Pour la tester, commencez par démarrer MongoDB sur votre machine, puis, à partir du répertoire principal de l’application lancez la commande play puis run et rendez-vous à l’adresse localhost:9000/users.

Normalement vous devriez avoir un écran comme celui-ci :

Play CRUD page

Vous pouvez alors créer et supprimer des utilisateurs \o/

Si vous avez oublié de démarrer votre base MongoDB, vous aurez une erreur comme celle-ci :

Play error missing database

Dans ce cas, il faut arrêter l’application, démarrer MongoDB et démarrer à nouveau votre application.

Voilà ! J’espère que cette petite mise en bouche vous aura fait partir du bon pied

Pour les “flemmards”, vous pouvez directement télécharger l’archive du projet.

Pour ceux qui veulent partir directement d’une application intégrant les composants de base, j’ai créé un projet de démarrage librement accessible sur github : github.com/loicknuchel/play-starter

What’s next

Pour ceux qui veullent aller un peu plus loin, je conseille le workshop buyme de Scala.io : github.com/workshop-buyme/buyme/wiki