Servicios REST con Spring MVC y AngularJS
0. Índice de contenidos.
- 1. Introducción.
- 2. Entorno.
- 3. Configuración del proyecto
- 4. Servicios REST con Spring MVC
- 5. Consumir los servicios REST con AngularJS
- 6. Conclusiones.
1. Introducción.
En este tutorial vamos a montar un pequeño proyecto donde vamos a dar de alta un par de servicios REST con Spring MVC y los vamos a consumir desde una aplicación en AngularJS. Los servicios (o recursos) REST se consideran entidades que representan conceptos de negocio. Actualmente se está trabajando mucho para construir en las organizaciones APIs REST que expongan su negocio de forma sencilla para ser consumidos por diferentes aplicaciones. Veremos cómo implementar los recursos REST con Spring MVC y su consumo a través de una aplicación hecha en AngularJS.
Si quieres descargar el código fuente del tutorial pincha aquí.
2. Entorno.
El tutorial se ha realizado con el siguiente entorno:
- MacBook Pro 15′ (2.4 GHz Intel Core i5, 8GB DDR3 SDRAM).
- Oracle Java SDK 1.7.0_60
- Spring Boot 1.1.10.RELEASE
- Spring MVC 4.0.8.RELEASE
- AngularJS 1.2.21
3. Configuración del proyecto
Lo primero será crear el proyecto por lo que usaremos Maven para ello. En el pom.xml metemos lo siguiente:
4.0.0 com.autentia.tutoriales springmvc-angular 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-parent 1.1.10.RELEASE org.springframework.boot spring-boot-starter-thymeleaf org.springframework.boot spring-boot-maven-plugin
Utilizaremos el spring-boot-starter-parent para utilizar las dependencias comunes de un proyecto Spring. También añadimos la dependencia spring-boot-starter-thymeleaf para utilizar el motor de plantillas Thymeleaf ya que en nuestro caso las vistas se construirán en HTML5 y AngularJS.
4. Servicios REST con Spring MVC
Para la prueba de concepto crearemos un API REST con un endpoint que devuelva un listado de películas con la información en formato JSON del título, año del estreno y el nombre del director. También haremos otro endpoint para añadir una película al catálogo desde la página web. El formato y las URLs serían las siguientes:
HTTP GET /films
Respuesta:
[ { title: "12 years a slave", year: 2013, director: "Steve McQueen" }, { title: "Argo", year: 2012, director: "Ben Affleck" }, { title: "The Artist", year: 2011, director: "Michel Hazanavicius" } ]
HTTP POST /films
Petición:
{ title: "No Country for Old Men", year: 2007, director: "Joel y Ethan Coen" }
El código que cubre el API REST lo añadimos en la clase FilmsController, para ello la anotamos con @RestController. Esta anotación de Spring MVC proporcionará superpoderes REST a la clase. Los métodos anotados con @RequestMapping y el verbo HTTP correspondiente (GET, POST) se encargarán de representar los endpoints de nuestra API de películas. Es sólo un ejemplo por lo que las películas las meto en una lista que me creo en la propia clase.
package com.autentia.tutoriales; import java.util.ArrayList; import java.util.List; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(value = "/films") public class FilmsController { private static final List<Film> DUMMY_FILMS = new ArrayList<Film>(); static { DUMMY_FILMS.add(new Film("12 years a slave", 2013, "Steve McQueen")); DUMMY_FILMS.add(new Film("Argo", 2012, "Ben Affleck")); DUMMY_FILMS.add(new Film("The Artist", 2011, "Michel Hazanavicius")); DUMMY_FILMS.add(new Film("The King's speech", 2010, "Tom Hooper")); DUMMY_FILMS.add(new Film("The Hurt Locker", 2009, "Kathryn Bigelow")); DUMMY_FILMS.add(new Film("Slumdog Millionaire", 2008, "Danny Boyle")); DUMMY_FILMS.add(new Film("No Country for Old Men", 2007, "Joel y Ethan Coen")); } @RequestMapping(method = RequestMethod.GET) public List<Film> getFilms() { return DUMMY_FILMS; } @RequestMapping(method = RequestMethod.POST) public void addFilm(@RequestBody @Valid Film film) { DUMMY_FILMS.add(film); } }
Automáticamente y sin necesidad de configurar nada Spring MVC se encargará de serializar y deserializar de JSON a Java y viceversa.
La anotación @RequestBody se utiliza para indicar que el objeto film vendrá en el cuerpo de la petición. La anotación @Valid se utiliza para lanzar las validaciones del estándar JSR 303 Bean Validation.
La clase Film es un POJO normal y corriente:
package com.autentia.tutoriales; import javax.validation.constraints.NotNull; import org.hibernate.validator.constraints.NotEmpty; public class Film { @NotEmpty private String title; @NotNull private Integer year; @NotEmpty private String director; private Film() { } public Film(String title, Integer year, String director) { this.title = title; this.year = year; this.director = director; } public String getTitle() { return title; } public Integer getYear() { return year; } public String getDirector() { return director; } }
Con esto tenemos nuestro API Rest preparado. Nos faltarán un par de clases: una para configurar el arranque de la aplicación a través de Spring Boot y la otra para redireccionar a la página de inicio index.html
package com.autentia.tutoriales; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan @EnableAutoConfiguration public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Para no tener que configurar pesados ficheros XML queda mucho más limpia la configuración de esta manera.
package com.autentia.tutoriales; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class AppController { @RequestMapping(value = "/", method = RequestMethod.GET) String home() { return "index"; } }
Cuando entremos a la URL http://localhost:8080/ nos redirigirá a nuestro index.html.
5. Consumir los servicios REST con AngularJS
Una vez montado todo el API REST sólo nos queda hacer la página donde visualizar el catálogo de las películas. Para ello nos construimos una página index.html.
El código HTML es sencillo. Las directivas de Angular se utilizan para que éste pueda manejar el contenido del HTML y que pueda hacer su magia. Se recoge de la variable ‘films’ que almacena el catálogo con la respuesta del servidor, y se recorre para sacar cada una de los datos de cada película y pintarlo en la página. Debajo aparece el formulario con los campos para añadir una nueva película al catálogo.
<!DOCTYPE html> <html ng-app="films"> <head> <meta charset="UTF-8" /> <title>Oscar a la mejor película</title> </head> <body ng-app="springmvc-angular" ng-controller="FilmsController" ng-init="getFilms()"> <div class="container" ng-show="films != null"> <div class="film-info-bottom" ng-repeat="film in films"> <h4><span> {{film.year}} - {{film.title}} - {{film.director}} </span></h4> </div> </div> <div class="form"> <label for="title">Título:</label> <input id="title" ng-model="title" type="text" /> <label for="year">Año:</label> <input id="year" ng-model="year" type="number" /> <label for="director">Director:</label> <input id="director" ng-model="director" type="text" /> <button id="addBtn" class="btn" ng-click="addFilm()">Añadir película</button> </div> <h4>{{msg}}</h4> <script src="/wp-content/uploads/tutorial-data/http://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.js"></script> <script src="/wp-content/uploads/tutorial-data/http://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular-resource.js"></script> <script src="/wp-content/uploads/tutorial-data/./js/services.js"></script> </body> </html>
En el fichero services.js se añade el código que se encargará de hacer las llamadas al API REST y manejar la respuesta en formato JSON. Mediante el servicio $http.get realizamos la comunicación con el servidor. Le indicamos el endpoint al que debe llamar haciendo una llamada tipo GET de HTTP. Cuando el servidor responde con el resultado de la llamada GET /films se ejecutará la promesa que invoca a la función que se le pasa por parámetro al success en caso de que la respuesta venga con código 200. Dentro del success se almacena el contenido de la respuesta en la variable films. En caso de error se llamará al método error que únicamente muestra un mensaje de error.
var app = angular.module('films', [ "ngResource" ]); app.controller('FilmsController', [ '$scope', '$http', function($scope, $http) { $scope.getFilms = function() { $http.get('/films').success(function(data) { $scope.films = data; }); } $scope.addFilm = function() { $http.post('/films', { title : $scope.title, year : $scope.year, director : $scope.director } ).success(function(data) { $scope.msg = 'Pelicula creada correctamente'; $scope.getFilms(); }).error(function(data) { $scope.msg = 'Se ha producido un error'; }); } } ]);
Arrancamos el servidor con el comando mvn spring-boot:run y entramos en http://localhost:8080.
6. Conclusiones.
Hemos podido ver lo sencillo que se vuelve el desarrollo web cuando utilizas determinada tecnología que está especialmente pensada para facilitar el desarrollo a los programadores. Tanto AngularJS como Spring MVC son sencillos de utilizar y casi no tienen configuración por lo que con pocas líneas tienes la funcionalidad lista.
Tanto para pequeñas pruebas de concepto como grandes proyectos con cientos de recursos REST esta combinación es perfectamente posible.
Si quieres descargar el código fuente del tutorial pincha aquí
Espero que te haya sido de ayuda.
Un saludo.
Juan
Buen aporte!
Que buen aporte !!! Muchas Gracias !!!
Muy bueno pero me gustaria saber cual es la forma común para configurar la conexión a la base de datos en un proyecto con el mismo esqueleto.
Gracias por el aporte
¿Usas tomcat?
¿Cómo ejecutas el servicio web?
hola oye me gustaría saber como validas del lado del servidor
como muestras el error en pantalla gracias ojala y pudieras ayudarme
Hola Juan ,
Que servidor utilizaste para este ejemplo ?
Groso! Muy bue aporte. Lo voy a usar tal cual para arrancar con angular y servicios REST.
Solo que voy a deployar en un Tomcat es lugar de Spring-boot :D.
Gracias!
Disculpa, Yo no entiendo dónde se crea los archivos JSON, me refiero a que dónde los colocas, algunas rutas en especial, en el wepapp?
@Ares. El manejo de los formatos JSON los hace la anotacion @RequestBody de Spring, el se encarga de serializar y deserializar las peticiones en formato JSON
Muchísimas gracias! Muy bueno y claro
Muy bueno y sobretodo claro.
Mil gracias por compartir tus conocimientos.