¿Qué es Scala?
Scala es un lenguaje de programación multi-paradigma diseñado para expresar patrones comunes de programación en forma concisa, elegante y con tipos seguros. Integra sutilmente características de lenguajes funcionales y orientados a objetos. La implementación actual corre en la máquina virtual de Java y es compatible con las aplicaciones Java existentes.más información en:
https://www.scala-lang.org/
¿Qué es Play Framework?
Play es un framework de aplicación web de código abierto, escrito en Scala y también utilizable desde otros lenguajes de programación compilados a Bytecode, p. Java (Play incluye una API de Java en versiones más recientes), que sigue el patrón de arquitectura model-view-controller (MVC). Su objetivo es optimizar la productividad del desarrollador mediante el uso de convenciones sobre la configuración, la recarga de código en caliente y la visualización de errores en el navegadorScala y Play son una combinación perfecta para desarrollar aplicaciones que requieran de mucha demanda o millones de transacciones o peticiones por segundo, su diseño stateless (Sin estado) permite que Play Framework con Scala sean los elegidos para ambientes Cluster y que requieran de alto performance gracias a que también permiten operaciones asíncronas en el lado del servidor.
¿Qué necesitaremos para realizar nuestro CRUD?
- IntelliJ IDEA Community Edition
- Una computadora con Linux, Windows, Mac OSX o cualquier SO compatible.
- Instalar SBT http://www.scala-sbt.org/0.13/docs/es/Installing-sbt-on-Mac.html
- Necesitaras utilizar alguna plantilla, te recomiendo la Starter https://github.com/playframework/play-scala-starter-example/tree/2.6.x
La estructura de directorios final de nuestro proyecto será la siguiente:
Comenzamos
El primer paso será configurar nuestro proyecto es decir indicar las rutas y acceso a bases de datos. Esto lo realizaremos en los archivos conf/application.conf, conf/routes y build.sbt.
Configurando build.sbt
Para que nuestro proyecto se conecte apropiadamente utilizando JDBC necesitamos agregar las siguientes dependencias.
libraryDependencies += jdbc
libraryDependencies += "org.postgresql" % "postgresql" % "9.4-1206-jdbc42"
Ej.
Configurando Application.conf
El application.conf es un archivo muy útil ya que permite definir ciertas configuraciones como la conexión a base de datos de nuestro proyecto.Ej.
Configurando routes.
El archivo routes será el que nos permitirá definir las rutas de acceso a nuestros controladores, los importantes en este proyecto son:
style="background-color: white; font-family: Menlo; font-size: 9pt;"># Home page GET / controllers.TaskController.list # Tasks GET /tasks controllers.TaskController.list POST /newTask controllers.TaskController.newTask GET /addTaskView controllers.TaskController.addTaskView GET /updateTaskView/:id/:label controllers.TaskController.updateTaskView(id: Long, label: String) POST /deleteTask/:id controllers.TaskController.deleteTask(id:Long) POST /tasks/update/:id/:label controllers.TaskController.updateTask(id: Long, label: String)
Las rutas anteriores contienen las operaciones básicas de alta, modificación y baja de datos en
la tabla "task" que será objeto de uso en nuestro ejemplo.
Creando nuestro modelo.
Play Framework utiliza el patrón de diseño modelo - vista - controlador (MVC) por lo tanto
iniciaremos creando nuestro modelo.
Para ello en el directorio models crearemos una clase Scala llamada Task.scala.
package models import play.api.db._ import anorm._ import anorm.SqlParser._ import javax.inject.{Inject, Singleton} case class TaskModel(id: Long, label: String) @Singletonclass Task @Inject() (dBApi: DBApi){ private val db = dBApi.database("default") val task = { get[Long]("id") ~ get[String]("label") map { case id ~ label => TaskModel(id, label) } } def all(): List[TaskModel] = db.withConnection { implicit c => SQL("select * from task").as(task *) } def create(label: String) { db.withConnection { implicit c => SQL("insert into task (label) values ({label})").on( 'label -> label ).executeUpdate() } } def update(id: Long, label: String){ db.withConnection{ implicit c => SQL("UPDATE task SET label = {label} WHERE id = {id}").on( 'id -> id, 'label -> label ).executeUpdate() } } def delete(id: Long) { db.withConnection { implicit c => SQL("delete from task where id = {id}").on( 'id -> id ).executeUpdate() } } }
Creando nuestras vistas.
Luego procedemos a crear nuestras vistas en el directorio "views". Para ello utilizaremos
una plantilla basada en el archivo main.scala.html.
Archivo main.scala.html.
@* * This template is called from the `index` template. This template * handles the rendering of the page header and body tags. It takes * two arguments, a `String` for the title of the page and an `Html` * object to insert into the body of the page. *@ @(title: String)(content: Html) <!DOCTYPE html> <html lang="en"> <head> @* Here's where we render the page title `String`. *@ <title>@title</title> <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/bootstrap-theme.min.css")"> <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/bootstrap.min.css")"> <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")"> <script src="@routes.Assets.versioned("javascripts/jquery-3.2.1.min.js")" type="text/javascript"></script> <script src="@routes.Assets.versioned("javascripts/bootstrap.min.js")" type="text/javascript"></script> </head> <body> @* And here's where we render the `Html` object containing * the page content. *@ @content </body></html>
Archivo addTask.scala.html.
@(taskForm: Form[String])(implicit messages: Messages) @import helper._ @main("Welcome to Play") { @* * Get an `Html` object by calling the built-in Play welcome * template and passing a `String` message. *@ <div id="main"> <h2>Agregar una nueva nota</h2> @form(routes.TaskController.newTask) { <div class="form-group"> <label for="label">Nota</label> <input type="text" class="form-control" name="label" id="label" required="required" placeholder="Ingresar la nota"> </div> <div class="form-group"> <input type="submit" class="btn btn-default" value="Crear"> <input type="reset" class="btn btn-default" value="Cancelar"> </div> } <a href='@routes.TaskController.list'>Show list</a> </div> }Archivo tasks.scala.html@(tasks: List[TaskModel])(implicit messages: Messages, req: RequestHeader) @import helper._ @main("Welcome to Play") { @* * Get an `Html` object by calling the built-in Play welcome * template and passing a `String` message. *@ <div id="main"> <h1>@tasks.size tasks</h1> <div class="add"> <a href='@routes.TaskController.addTaskView'><button type="button" class="btn btn-primary">Agregar</button></a> </div> <div class="table-responsive"> <table class="table"> <tr> <th>id</th><th>label</th><th>Update</th><th>Delete</th> </tr> @tasks.map { task => <tr> <td>@task.id</td> <td>@task.label</td> <td><a href="@routes.TaskController.updateTaskView(task.id,task.label)"> <button type="button" class="btn btn-info">Actualizar</button></a></td> <td><button type="button" data-id="@task.id" id="btn-modal-delete" class="btn btn-danger" data-toggle="modal" data-target="#myModal">Eliminar</button></td> </tr> @*routes.TaskController.deleteTask(task.id)*@ } </table> </div> <!-- Modal --> <div id="myModal" class="modal fade" role="dialog"> <div class="modal-dialog"> <!-- Modal content--> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> <h4 class="modal-title">Modal Header</h4> </div> <div class="modal-body"> <p>Esta seguro en eliminar el registro?</p> <input type="hidden" id="data-id"/> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" id="btnEliminar" data-dismiss="modal">Aceptar</button> <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button> </div> </div> </div> </div> </div> <script type="text/javascript"> $(document).on('click','#btn-modal-delete', function(e){ var taskId = $(this).data('id'); console.log("taskId:" + taskId); $('.modal-body #data-id').val(taskId); }); $('.modal-dialog .modal-footer').on('click','#btnEliminar', function(e) { var id = $('.modal-body #data-id').val(); console.log(id); $.ajax({ type: 'POST', url: '/deleteTask/'+ id, success: function(data) { document.open(); document.write(data); document.close(); } }); return false; }); </script> }Archivo updateTaskView.scala.html.@(id: Long, label: String)(implicit messages: Messages) @import helper._ @main("Welcome to Play") { @* * Get an `Html` object by calling the built-in Play welcome * template and passing a `String` message. *@ <div id="main"> @form(routes.TaskController.updateTask(id, label)) { <input type="text" value="@id" name="id" class="form-control"> <input type="text" value="@label" name="label" class="form-control"> <input type="submit" class="btn btn-default" value="Update"> } </div> }Con esto ya tenemos listas nuestras vistas. Ahora procederemos a crear nuestros controladoresCreando nuestros controladores.
Para nuestro ejemplo sencillo solo crearemos un controlador llamado TaskController. En nuestrocontrolador definiremos las diferentes acciones que realizaremos con nuestro modelo y vistas.Los controladores por lo general deben ir en el directorio "controllers".package controllers
import javax.inject.{Inject, Singleton} import forms.TaskForm import models.Task import play.api.mvc.{Action, Controller} import play.api.i18n.{I18nSupport, MessagesApi} @Singletonclass TaskController @Inject()(val messagesApi: MessagesApi)(task: Task) extends Controller with I18nSupport { def list = Action {implicit request => Ok(views.html.tasks(task.all())); } def addTaskView = Action { Ok(views.html.addTask(TaskForm.getForm)); } def updateTaskView(id: Long, label: String) = Action { Ok(views.html.updateTaskView(id, label)); } def newTask = Action { implicit request => TaskForm.getForm.bindFromRequest.fold( errors => BadRequest(views.html.tasks(task.all())), label => { task.create(label) Redirect(routes.TaskController.list) } ) } def updateTask(id: Long, label: String) = Action { implicit request => TaskForm.getForm.bindFromRequest.fold( errors => BadRequest(views.html.tasks(task.all)), label => { task.update(id, label) Redirect(routes.TaskController.list) } ) } def deleteTask(id: Long) = Action {request => task.delete(id); Redirect(routes.TaskController.list) } } Listo. Ahora procederemos a crear nuestra base de datos en PGAdmin 4para PostGreSQL. Crearemos una base de datos llamada "test" y a modo de ejemplo tambiéncrearemos una tabla llamada "task" con dos campos llamados "id" y "label".Luego nada más nos resta iniciar el servidor Netty, para lo cuál abrimos la consola o terminalnos dirigimos a el path del proyecto y haremos uso de los comandos:sbt : Para iniciar Scala Build Toolsclean: para limpiar el proyectocompile: Para compilar nuestro proyectorun: para iniciar el servidor de aplicación.
si probamos nuestro localhost puerto 9000 podremos notar nuestro CRUD funcionando a la perfección, cabe aclarar que se utilizaron otras herramientas como Bootstrap y JQuery Las cuales pienso explicar en otro post.
Espero les sea de utilidad y recuerden si desean un tema especifico solo escriban en los comentarios y yo procedo a hablar al respecto. También agradecerles a quienes colaboran vía PayPal y con los anuncios para que este blog siga vigente. Hasta el siguiente post.