0. Indicar el acceso a una página Thymeleaf
Para ello tenemos que crear un controlador que contenga las anotaciones siguientes:
@Controller:
Anotación de clase que indica que es un controlador
@RequestMapping("/")
Anotación de clase o método que indica donde localizar un servicio web
Además debemos actualizar el modelo para que Thymeleaf pueda acceder a estas variables que guarda el modelo.
package com.ximodante; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.ui.Model; @Controller public class ViewController { private String appMode; @Autowired public ViewController(Environment env){ appMode=env.getProperty("app-mode"); } @RequestMapping("/") public String index(Model model){ model.addAttribute("datetime", new Date()); model.addAttribute("username", "Informatica Dantesca"); model.addAttribute("mode", "production"); return "index"; } }
1. Crear una página Thymeleaf
Por otra parte, para mostrar una plantilla de Thymeleaf, tenemos que hacer estos pasos:
1. Colocar las librerías javascript o css que vayamos a utilizar en la carpeta scr/main/resources/static. Si queremos ser mas organizados se podran crear diferentes carpetas dentro de static (por ejemplo una para los "css", otra para los "js", etc). En nuestro caso vamos a descargar, desde sus respectivas webs:
2. Crear una plantilla Thymeleaf en la carpeta scr/main/resources/static/templates. En nuestro caso le vamos a llamar index.html .
Vamos a ver pequeños detalles
2. Separación de comportamiento entre producción y desarrollo
En Thymeleaf haremos uso de las clausulas condicionales "if". En el modelo podemos incluir una variable llamada "mode" que tome valores "development" o "production". Si es en desarrollo, vamos a utilizar las librería "bootstrap.min.css", mientras en producción vamos a utilizar "bootstrap.css". Para ello incluimos el siguiente código:<link th:if="${mode == 'development'}" rel="stylesheet" href="../static/bootstrap.css" th:href="@{/bootstrap.css}" /> <link th:if="${mode == 'production'}" rel="stylesheet" href="../static/bootstrap.min.css" th:href="@{/bootstrap.min.css}" />
Thymeleaf también permite formatear variables. En este caso la fecha (que en el modelo la hemos guardado con el nombre "datetime"
<p th:text="${#dates.format(datetime,'dd MMM yyyy HH:mm:ss')}" class="text-muted">Page was rendered today.</p>
3. Inclusión de código Angular 1.xx en la plantilla
No es mi misión explicar como va Angular. Pero veamos algunos detalles:Indicación de la aplicación y módulo de código realizados en Angular, en nuestro caso lo hemos indicado en el <body>. Observar que el controlador tiene el alias "vm".
<body ng-app="app" ng-controller="BookingsController as vm">
Para ver el contenido de las variables en angular hemos utilizado {{vm.variable}} o similar.
Tambien utilizamos la archirepetida cláusula ng-repat
El contenido de la plantilla Thymeleaf va a ser el siguiente:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>Hotel Booking App</title> <link th:if="${mode == 'development'}" rel="stylesheet" href="../static/bootstrap.css" th:href="@{/bootstrap.css}" /> <link th:if="${mode == 'production'}" rel="stylesheet" href="../static/bootstrap.min.css" th:href="@{/bootstrap.min.css}" /> <script type="text/javascript" src="/static/angular.min.js" th:src="@{angular.min.js}"></script> <script type="text/javascript" src="/static/app/module.js" th:src="@{/app/app.module.js}"></script> <script type="text/javascript" src="/static/app/bookings.controller.js" th:src="@{/app/bookings.controller.js}"></script> </head> <body ng-app="app" ng-controller="BookingsController as vm"> <header> <nav class="navbar navbar-default"> <div class="container-fluid"> <a class="navbar-brand" href="#"> Booking Demo JAJAJAJA</a> </div> <p class="navbar-text navbar-right" th:text="'Signed as ' + ${username}" style="margin-right: 10px:">Signed as Anonymous</p> </nav> </header> Hello Bootstrap! How are you Folk? And you, Thymeleaf? <div>{{vm.prova}}</div> <div> <div class="row"> <div class="col-lg-offset-2 col-lg-8"> <!-- Get all booking or only affordable ones --> <div class = "btn-group" role="group"> <button ng-click = "vm.getAll()" type="button" class = "btn btn-default">All</button> <button ng-click = "vm.getAffordable()" type="button" class = "btn btn-default">Less than {{vm.min}}</button> </div> <!-- Display bookings in a table --> <table class="table"> <thead> <tr> <th>Hotel</th> <th>Nights</th> <th>Price</th> <th>Total</th> <th style="width: 90px"></th> </tr> </thead> <tr ng-repeat="booking in vm.bookings"> <td>{{booking.hotelName}}</td> <td>{{booking.nbOfNights}}</td> <td>{{booking.pricePerNight}}</td> <td>{{booking.totalPrice}}</td> <td> <button class="btn btn-danger" ng-click="vm.deleteBooking(booking.id)">Delete</button> </td> </tr> </table> </div> </div> </div> <footer class="footer" style="position:absolute; bottom:0;background-color: #f5f5f5;"> <div class="container"> <p th:text="${#dates.format(datetime,'dd MMM yyyy HH:mm:ss')}" class="text-muted">Page was rendered today.</p> </div> </footer> </body> </html>
4. Creación del código js de ángular
Para ello vamos a utilizar la carpeta scr/main/resources/static/templates para guardar 2 ficheros angular:- app.module.js (aplicación)
- bookings.controller.js (controlador)
Normalmente en angular se tiene una aplicación y varios módulos que dependen de ella. En este caso solo tenemos una aplicación.
Veamos su código
(function(){ 'use strict'; angular.module('app',[]); })();
Poco puedo decir yo aquí. Veamos el otro código. Aquí hay que remarcar como hacemos peticiones GET y POST con ángular a nuestros servicios REST, que hemos definido
Veamos como hacemos una petición GET que nos devuleve una promesa:
function getAll(){ var url = "/bookings/all"; var bookingsPromise = $http.get(url); bookingsPromise.then(function(response) { vm.bookings = response.data; }); }
Veamos como realiza una petición POST
function deleteBooking(id){ var url = "/bookings/delete/" + id; $http.post(url).then(function(response){ vm.bookings = response.data; }); }
Tambien hay que publicar las funciones creadas:
vm.bookings = []; vm.getAll = getAll; vm.getAffordable = getAffordable; vm.deleteBooking = deleteBooking; vm.prova="Mi prueba"; vm.min=23;
Y el contenido final del fichero js booking.controller.js es:
(function () { 'use strict'; angular .module('app') .controller('BookingsController',BookingsController); BookingsController.$inject = ['$http']; function BookingsController($http) { var vm = this; vm.bookings = []; vm.getAll = getAll; vm.getAffordable = getAffordable; vm.deleteBooking = deleteBooking; vm.prova="Mi prueba"; vm.min=23; init(); function init(){ getAll(); } function getAll(){ var url = "/bookings/all"; var bookingsPromise = $http.get(url); bookingsPromise.then(function(response) { vm.bookings = response.data; }); } function getAffordable(){ var url = "/bookings/affordable/" + vm.min; var bookingsPromise = $http.get(url); bookingsPromise.then(function(response) { vm.bookings = response.data; }); } function deleteBooking(id){ var url = "/bookings/delete/" + id; $http.post(url).then(function(response){ vm.bookings = response.data; }); } } })();