Activitats

Creació d'un servei web RESTFul amb NetBeans

L’objectiu d’aquesta activitat és veure les facilitats que us aporta NetBeans en la creació d’un servei web RESTful i com els seus assistents us permeten treballar fàcilment amb fonts de dades persistents i crear automàticament els serveis web RESTful per fer les operacions típiques de CRUD amb aquests recursos.

Creeu un servei web RESTful amb Java EE 7 que permeti les operacions típiques CRUD sobre una entitat Book representada tal com es pot veure en la figura.

Figura Entitat Book

Cal que creeu el servei web fent servir els assistents que proporciona NetBeans començant per la creació de la taula a la base de dades que contindrà el catàleg de llibres.

La solució de l’exercici s’ha provat amb la versió 4.1.1 de GlassFish.

En aquesta activitat fareu “enginyeria inversa”: primer creareu la taula a la base de dades que contindrà el catàleg de llibres, després creareu una entitat JPA que representarà el model del domini i, a partir d’aquesta entitat, creareu el servei web RESTful, que implementarà les operacions CRUD per a l’entitat.

Començareu l’activitat creant la taula a la base de dades que contindrà el catàleg de llibres. Per fer-ho, aneu a la pestanya Services de NetBeans i a Databases / jdbc:derby:localhost:1527/sample [app on APP], feu clic amb el botó dret i Connect. Un cop connectada la base de dades aneu a APP / Tables, feu clic amb el botó dret i creeu una nova taula anomenada “BOOK” (vegeu la figura).

Figura Creació de la taula “BOOK”

Creeu tres columnes a la taula i anomeneu-les “ISBN” (que serà la clau primària), “AUTHOR” i “TITLE”(vegeu la figura).

Figura Especificació de la taula “BOOK”

Afegiu alguns llibres a la taula, tal com es pot veure en la figura.

Figura Llibres del catàleg

Creeu el projecte “nb-restbooksioc” a NetBeans. Per fer-ho, feu New Project… / Maven / Web Application (vegeu la figura).

Figura Creació del projecte

Polseu Next i ompliu el formulari especificant el nom del projecte (vegeu la figura).

Figura Dades del projecte

En la següent pantalla (vegeu la figura) de l’assistent, deixeu els valors per defecte i polseu Finish.

Figura Configuració del projecte

Per fer la transformació entre objectes Java i JSON i a l’inrevés cal que importeu Jersey i Jackson com a artefactes al pom.xml. Afegiu aquestes línies al pom.xml:

  1. <dependency>
  2. <groupId>org.glassfish.jersey.core</groupId>
  3. <artifactId>jersey-server</artifactId>
  4. <version>2.22.1</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.sun.jersey</groupId>
  8. <artifactId>jersey-json</artifactId>
  9. <version>1.19</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.glassfish.jersey.media</groupId>
  13. <artifactId>jersey-media-json-jackson</artifactId>
  14. <version>2.22.1</version>
  15. </dependency>

Ja teniu la taula que guardarà els llibres a la base de dades creada i el projecte que us servirà de base també creat i configurat. Ara generareu una entitat JPA que faci el mapatge de les dades de la taula de llibres en un objecte Java que anomenareu Book. Per fer-ho, feu clic amb el botó dret al projecte “nb-restbooksioc” i seleccioneu New / Entity Classes from Database (vegeu la figura).

Figura Creació de l’entitat JPA

Trieu el datasource jdbc/sample i la taula “BOOK” i polseu Next (vegeu la figura).

Figura Selecció de la taula

A la següent pantalla de l’assistent deixareu els valors per defecte i polsareu Next (vegeu la figura).

Figura Classes a generar

Per a les opcions de mapatge també deixareu els valors per defecte i polsareu Finish (vegeu la figura).

Figura Opcions de mapatge

NetBeans ens ha generat una entitat JPA anomenada Book al paquet cat.xtec.ioc.nb.restbooksioc amb tot el codi necessari per fer-la persistent a la taula “BOOK”. No entrarem en detall en aquest codi, ja que no és l’objectiu de l’activitat.

  1. @Table(name = "BOOK")
  2. @XmlRootElement
  3. @NamedQueries({
  4. @NamedQuery(name = "Book.findAll", query = "SELECT b FROM Book b"),
  5. @NamedQuery(name = "Book.findByIsbn", query = "SELECT b FROM Book b WHERE b.isbn = :isbn"),
  6. @NamedQuery(name = "Book.findByAuthor", query = "SELECT b FROM Book b WHERE b.author = :author"),
  7. @NamedQuery(name = "Book.findByTitle", query = "SELECT b FROM Book b WHERE b.title = :title")})
  8. public class Book implements Serializable {
  9.  
  10. private static final long serialVersionUID = 1L;
  11. @Id
  12. @Basic(optional = false)
  13. @NotNull
  14. @Size(min = 1, max = 30)
  15. @Column(name = "ISBN")
  16. private String isbn;
  17. @Size(max = 255)
  18. @Column(name = "AUTHOR")
  19. private String author;
  20. @Size(max = 255)
  21. @Column(name = "TITLE")
  22. private String title;
  23.  
  24. public Book() {
  25. }
  26.  
  27. public Book(String isbn) {
  28. this.isbn = isbn;
  29. }
  30.  
  31. public String getIsbn() {
  32. return isbn;
  33. }
  34.  
  35. public void setIsbn(String isbn) {
  36. this.isbn = isbn;
  37. }
  38.  
  39. public String getAuthor() {
  40. return author;
  41. }
  42.  
  43. public void setAuthor(String author) {
  44. this.author = author;
  45. }
  46.  
  47. public String getTitle() {
  48. return title;
  49. }
  50.  
  51. public void setTitle(String title) {
  52. this.title = title;
  53. }
  54.  
  55. @Override
  56. public int hashCode() {
  57. int hash = 0;
  58. hash += (isbn != null ? isbn.hashCode() : 0);
  59. return hash;
  60. }
  61.  
  62. @Override
  63. public boolean equals(Object object) {
  64. // TODO: Warning - this method won't work in the case the id fields are not set
  65. if (!(object instanceof Book)) {
  66. return false;
  67. }
  68. Book other = (Book) object;
  69. if ((this.isbn == null && other.isbn != null) || (this.isbn != null && !this.isbn.equals(other.isbn))) {
  70. return false;
  71. }
  72. return true;
  73. }
  74.  
  75. @Override
  76. public String toString() {
  77. return "cat.xtec.ioc.nb.restbooksioc.Book[ isbn=" + isbn + " ]";
  78. }
  79.  
  80. }

Un cop teniu ja creada l’entitat JPA Book ja podeu generar el servei web RESTful, que us permetrà fer les operacions CRUD al catàleg de llibres.

Per fer-ho, feu clic amb el botó dret al projecte “nb-restbooksioc” i seleccioneu New / RESTful Web Services from Entity Classes… (vegeu la figura).

Figura Assistent de creació del servei web

Seleccioneu l’entitat JPA que acabeu de crear i polseu Next (vegeu la figura).

Figura Entitat JPA

Trieu el paquet on voleu que us generi el codi del servei web, per exemple a cat.xtec.ioc.nb.restbooksioc.service (vegeu la figura).

Figura Paquet on es generarà l’entitat JPA

Feu clic a Finish i veureu que s’han generat tres classes al paquet cat.xtec.ioc.nb.restbooksioc.service:

  • La classe AbstractFacade, que conté la implementació dels mètodes JPA per fer persistent l’entitat Book.
  • La classe ApplicationConfig, on, per defecte, us ha posat que els recursos RESTful seran accessibles al PATH webresources. Això implica que els recursos seran accessibles a l’URL localhost:8080/nb-restbooksioc/webresources.
  • La classe BookFacadeREST, que és la implementació del servei web RESTful amb les operacions CRUD sobre el catàleg de llibres.

El codi generat a la classe BookFacadeREST és el següent:

  1. @Stateless
  2. @Path("books")
  3. public class BookFacadeREST extends AbstractFacade<Book> {
  4.  
  5. @PersistenceContext(unitName = "cat.xtec.ioc_nb-restbooksioc_war_1.0-SNAPSHOTPU")
  6. private EntityManager em;
  7.  
  8. public BookFacadeREST() {
  9. super(Book.class);
  10. }
  11.  
  12. @POST
  13. @Override
  14. @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  15. public void create(Book entity) {
  16. super.create(entity);
  17. }
  18.  
  19. @PUT
  20. @Path("{id}")
  21. @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  22. public void edit(@PathParam("id") String id, Book entity) {
  23. super.edit(entity);
  24. }
  25.  
  26. @DELETE
  27. @Path("{id}")
  28. public void remove(@PathParam("id") String id) {
  29. super.remove(super.find(id));
  30. }
  31.  
  32. @GET
  33. @Path("{id}")
  34. @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  35. public Book find(@PathParam("id") String id) {
  36. return super.find(id);
  37. }
  38.  
  39. @GET
  40. @Override
  41. @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  42. public List<Book> findAll() {
  43. return super.findAll();
  44. }
  45.  
  46. @GET
  47. @Path("{from}/{to}")
  48. @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
  49. public List<Book> findRange(@PathParam("from") Integer from, @PathParam("to") Integer to) {
  50. return super.findRange(new int[]{from, to});
  51. }
  52.  
  53. @GET
  54. @Path("count")
  55. @Produces(MediaType.TEXT_PLAIN)
  56. public String countREST() {
  57. return String.valueOf(super.count());
  58. }
  59.  
  60. @Override
  61. protected EntityManager getEntityManager() {
  62. return em;
  63. }
  64.  
  65. }

Podeu veure que s’han generat les següents operacions amb les corresponents anotacions JAX-RS:

  • Operació find: consulta d’un llibre mitjançant l’identificador (operació Read CRUD).
  • Operació create: creació d’un llibre al catàleg (operació Create CRUD).
  • Operació update: actualització de les dades d’un llibre (operació Update CRUD).
  • Operació remove: esborrar un llibre del catàleg (operació Delete CRUD).
  • Operació findAll: llistar tots els llibres del catàleg.

Per fer més entenedores les URI amb les quals provarem el servei web, canvieu @Path(“cat.xtec.ioc.nb.restbooksioc.book”) per @Path(“books”).

Ara sols cal que feu Clean and Build i després Run a NetBeans i es farà el desplegament al servidor d’aplicacions que tingueu configurat per al projecte (vegeu la figura).

Figura Desplegament del servei web

I utilitzeu cURL per fer provar les diferents operacions implementades; us en posem un parell com a exemple, la resta les podeu provar vosaltres mateixos.

Consulta de tots els llibres del catàleg:

curl localhost:8080/nb-restbooksioc/webresources/books

la sortida seria aquesta:

  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  2. <books>
  3. <book>
  4. <author>Ildefonso Falcones</author>
  5. <isbn>9788425343537</isbn>
  6. <title>La catedral del mar</title>
  7. </book>
  8. <book>
  9. <author>Jose Maria Peridis Perez</author>
  10. <isbn>9788467009477</isbn>
  11. <title>La luz y el misterio de las catedrales</title>
  12. </book>
  13. </books>

Alta d’un llibre al catàleg:

curl -H "Content-Type: application/xml" -X POST -d "<book><author>J.K. Rowling</author><isbn>9788499301518</isbn><title>Harry Potter y la piedra filosofal</title></book>" localhost:8080/nb-restbooksioc/webresources/books

Executeu la comanda anterior i després consulteu el llistat de llibres amb:

curl localhost:8080/nb-restbooksioc/webresources/books

Si tot ha anat bé veureu que el nou llibre s’ha afegit al catàleg de llibres:

  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  2. <books>
  3. <book>
  4. <author>Ildefonso Falcones</author>
  5. <isbn>9788425343537</isbn>
  6. <title>La catedral del mar</title>
  7. </book>
  8. <book>
  9. <author>Jose Maria Peridis Perez</author>
  10. <isbn>9788467009477</isbn>
  11. <title>La luz y el misterio de las catedrales</title>
  12. </book>
  13. <book>
  14. <author>J.K. Rowling</author>
  15. <isbn>9788499301518</isbn>
  16. <title>Harry Potter y la piedra filosofal</title>
  17. </book>
  18. </books>

El codi de la solució d’aquesta activitat el podeu descarregar del següent

enllaç ( 18.6 KB )
.

Anar a la pàgina següent:
Exercicis d'autoavaluació