From 4225df4a860b9288b440974e3bed78a98f37d22f Mon Sep 17 00:00:00 2001 From: Imanol Date: Thu, 7 Mar 2019 19:46:50 +0100 Subject: [PATCH] =?UTF-8?q?A=C3=B1ade=20toda=20la=20funcionalidad=20para?= =?UTF-8?q?=20mascotas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/mysql-with-inserts.sql | 11 + db/mysql.sql | 8 + .../uvigo/esei/daa/DAAExampleApplication.java | 4 +- .../java/es/uvigo/esei/daa/dao/PetDAO.java | 169 +++++++++++++++ .../java/es/uvigo/esei/daa/entities/Pet.java | 47 +++++ .../es/uvigo/esei/daa/rest/PetResource.java | 171 +++++++++++++++ src/main/webapp/js/dao/people.js | 12 ++ src/main/webapp/js/dao/pets.js | 52 +++++ src/main/webapp/js/view/people.js | 11 +- src/main/webapp/js/view/pets.js | 197 ++++++++++++++++++ src/main/webapp/pets.html | 50 +++++ 11 files changed, 730 insertions(+), 2 deletions(-) create mode 100644 src/main/java/es/uvigo/esei/daa/dao/PetDAO.java create mode 100644 src/main/java/es/uvigo/esei/daa/entities/Pet.java create mode 100644 src/main/java/es/uvigo/esei/daa/rest/PetResource.java create mode 100644 src/main/webapp/js/dao/pets.js create mode 100644 src/main/webapp/js/view/pets.js create mode 100644 src/main/webapp/pets.html diff --git a/db/mysql-with-inserts.sql b/db/mysql-with-inserts.sql index a35a952..9ce53af 100644 --- a/db/mysql-with-inserts.sql +++ b/db/mysql-with-inserts.sql @@ -14,6 +14,14 @@ CREATE TABLE `daaexample`.`users` ( PRIMARY KEY (`login`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `daaexample`.`pets` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(50) NOT NULL, + `peopleID` int NOT NULL, + PRIMARY KEY (`id`), + FOREIGN KEY (`peopleID`) REFERENCES people(id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + GRANT ALL ON `daaexample`.* TO 'daa'@'localhost' IDENTIFIED BY 'daa'; INSERT INTO `daaexample`.`people` (`id`,`name`,`surname`) VALUES (0,'Antón','Pérez'); @@ -30,3 +38,6 @@ INSERT INTO `daaexample`.`users` (`login`,`password`,`role`) VALUES ('admin', '713bfda78870bf9d1b261f565286f85e97ee614efe5f0faf7c34e7ca4f65baca','ADMIN'); INSERT INTO `daaexample`.`users` (`login`,`password`,`role`) VALUES ('normal', '7bf24d6ca2242430343ab7e3efb89559a47784eea1123be989c1b2fb2ef66e83','USER'); + +INSERT INTO `daaexample`.`pets` (`id`,`name`,`peopleID`) VALUES (0,'Greta',1); +INSERT INTO `daaexample`.`pets` (`id`,`name`,`peopleID`) VALUES (0,'Toby',2); diff --git a/db/mysql.sql b/db/mysql.sql index ed7cd93..420a55b 100644 --- a/db/mysql.sql +++ b/db/mysql.sql @@ -14,4 +14,12 @@ CREATE TABLE `daaexample`.`users` ( PRIMARY KEY (`login`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `daaexample`.`pets` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(50) NOT NULL, + `peopleID` int NOT NULL, + PRIMARY KEY (`id`), + FOREIGN KEY (`peopleID`) REFERENCES people(id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + GRANT ALL ON `daaexample`.* TO 'daa'@'localhost' IDENTIFIED BY 'daa'; diff --git a/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java b/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java index 2a67f22..0df167d 100644 --- a/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java +++ b/src/main/java/es/uvigo/esei/daa/DAAExampleApplication.java @@ -11,6 +11,7 @@ import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import es.uvigo.esei.daa.rest.PeopleResource; +import es.uvigo.esei.daa.rest.PetResource; import es.uvigo.esei.daa.rest.UsersResource; /** @@ -26,7 +27,8 @@ public class DAAExampleApplication extends Application { public Set> getClasses() { return Stream.of( PeopleResource.class, - UsersResource.class + UsersResource.class, + PetResource.class ).collect(toSet()); } diff --git a/src/main/java/es/uvigo/esei/daa/dao/PetDAO.java b/src/main/java/es/uvigo/esei/daa/dao/PetDAO.java new file mode 100644 index 0000000..75232aa --- /dev/null +++ b/src/main/java/es/uvigo/esei/daa/dao/PetDAO.java @@ -0,0 +1,169 @@ +package es.uvigo.esei.daa.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import es.uvigo.esei.daa.entities.Pet; + +/** + * DAO class for the {@link Pet} entities. + * + * @author Imanol Cobian Martinez + * + */ +public class PetDAO extends DAO { + + private final static Logger LOG = Logger.getLogger(PetDAO.class.getName()); + + public Pet get(int id) throws DAOException, IllegalArgumentException { + try (final Connection conn = this.getConnection()) { + final String query = "SELECT * FROM pets WHERE id=?"; + + try (final PreparedStatement statement = conn.prepareStatement(query)) { + statement.setInt(1, id); + + try (final ResultSet result = statement.executeQuery()) { + if (result.next()) { + return rowToEntity(result); + } else { + throw new IllegalArgumentException("Invalid id"); + } + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error getting a pet", e); + throw new DAOException(e); + } + } + + public List listAll() throws DAOException { + try (final Connection conn = this.getConnection()) { + final String query = "SELECT * FROM pets"; + + try (final PreparedStatement statement = conn.prepareStatement(query)) { + try (final ResultSet result = statement.executeQuery()) { + final List pets = new LinkedList<>(); + + while (result.next()) { + pets.add(rowToEntity(result)); + } + + return pets; + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error listing pets", e); + throw new DAOException(e); + } + } + + public List listByPeopleID(int peopleID) throws DAOException { + try (final Connection conn = this.getConnection()) { + final String query = "SELECT * FROM pets where peopleID=?"; + + try (final PreparedStatement statement = conn.prepareStatement(query)) { + statement.setInt(1, peopleID); + + try (final ResultSet result = statement.executeQuery()) { + final List pets = new LinkedList<>(); + + while (result.next()) { + pets.add(rowToEntity(result)); + } + + return pets; + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error listing pets", e); + throw new DAOException(e); + } + } + + public Pet add(String name, int peopleID) throws DAOException, IllegalArgumentException { + if (name == null) { + throw new IllegalArgumentException("name can't be null"); + } + + try (Connection conn = this.getConnection()) { + final String query = "INSERT INTO pets VALUES(null, ?, ?)"; + + try (PreparedStatement statement = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) { + statement.setString(1, name); + statement.setInt(2, peopleID); + + if (statement.executeUpdate() == 1) { + try (ResultSet resultKeys = statement.getGeneratedKeys()) { + if (resultKeys.next()) { + return new Pet(resultKeys.getInt(1), name, peopleID); + } else { + LOG.log(Level.SEVERE, "Error retrieving inserted id"); + throw new SQLException("Error retrieving inserted id"); + } + } + } else { + LOG.log(Level.SEVERE, "Error inserting value"); + throw new SQLException("Error inserting value"); + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error adding a pet", e); + throw new DAOException(e); + } + } + + public void modify(Pet pet) throws DAOException, IllegalArgumentException { + if (pet == null) { + throw new IllegalArgumentException("pet can't be null"); + } + + try (Connection conn = this.getConnection()) { + final String query = "UPDATE pets SET name=?, peopleID=? WHERE id=?"; + + try (PreparedStatement statement = conn.prepareStatement(query)) { + statement.setString(1, pet.getName()); + statement.setInt(2, pet.getPeopleID()); + statement.setInt(3, pet.getId()); + + if (statement.executeUpdate() != 1) { + throw new IllegalArgumentException("name and peopleID can't be null"); + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error modifying a pet", e); + throw new DAOException(); + } + } + + public void delete(int id) throws DAOException, IllegalArgumentException { + try (final Connection conn = this.getConnection()) { + final String query = "DELETE FROM pets WHERE id=?"; + + try (final PreparedStatement statement = conn.prepareStatement(query)) { + statement.setInt(1, id); + + if (statement.executeUpdate() != 1) { + throw new IllegalArgumentException("Invalid id"); + } + } + } catch (SQLException e) { + LOG.log(Level.SEVERE, "Error deleting a pet", e); + throw new DAOException(e); + } + } + + private Pet rowToEntity(ResultSet row) throws SQLException { + return new Pet( + row.getInt("id"), + row.getString("name"), + row.getInt("peopleID") + ); + } +} diff --git a/src/main/java/es/uvigo/esei/daa/entities/Pet.java b/src/main/java/es/uvigo/esei/daa/entities/Pet.java new file mode 100644 index 0000000..2a1c3d1 --- /dev/null +++ b/src/main/java/es/uvigo/esei/daa/entities/Pet.java @@ -0,0 +1,47 @@ +package es.uvigo.esei.daa.entities; + +import static java.util.Objects.requireNonNull; + +/** + * An entity that represents a pet. + * + * @author Imanol Cobian Martinez + */ +public class Pet { + + private int id; + private String name; + private int peopleID; + + Pet() {} + + public Pet(int id, String name, int peopleID) { + this.id = id; + this.setName(name); + this.setPeopleID(peopleID); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = requireNonNull(name, "Name can't be null"); + } + + public int getPeopleID() { + return peopleID; + } + + public void setPeopleID(int peopleID) { + this.peopleID = requireNonNull(peopleID, "PeopleID can't be null"); + } +} diff --git a/src/main/java/es/uvigo/esei/daa/rest/PetResource.java b/src/main/java/es/uvigo/esei/daa/rest/PetResource.java new file mode 100644 index 0000000..ad9d882 --- /dev/null +++ b/src/main/java/es/uvigo/esei/daa/rest/PetResource.java @@ -0,0 +1,171 @@ +package es.uvigo.esei.daa.rest; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.ws.rs.DELETE; +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import es.uvigo.esei.daa.dao.DAOException; +import es.uvigo.esei.daa.dao.PetDAO; +import es.uvigo.esei.daa.entities.Pet; + +/** + * REST resource for managing people. + * + * @author Imanol Cobian Martinez + */ +@Path("/pets") +@Produces(MediaType.APPLICATION_JSON) +public class PetResource { + + private final static Logger LOG = Logger.getLogger(PeopleResource.class.getName()); + + private final PetDAO dao; + + public PetResource() { + this(new PetDAO()); + } + + PetResource(PetDAO dao) { + this.dao = dao; + } + + @GET + @Path("/{id}") + public Response get( + @PathParam("id") int id + ) { + try { + final Pet pet = this.dao.get(id); + + return Response.ok(pet).build(); + } catch (IllegalArgumentException iae) { + LOG.log(Level.FINE, "Invalid pet id in get method", iae); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(iae.getMessage()) + .build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error getting a pet", e); + + return Response.serverError() + .entity(e.getMessage()) + .build(); + } + } + + @GET + public Response listAll() { + try { + return Response.ok(this.dao.listAll()).build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error listing pets", e); + return Response.serverError().entity(e.getMessage()).build(); + } + } + + @GET + @Path("/people{peopleID}") + public Response listByPeopleID( + @PathParam("peopleID") int peopleID + ) { + try { + return Response.ok(this.dao.listByPeopleID(peopleID)).build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error listing pets", e); + return Response.serverError().entity(e.getMessage()).build(); + } + } + + @POST + public Response add( + @FormParam("name") String name, + @FormParam("peopleID") int peopleID + ) { + try { + final Pet newPet = this.dao.add(name, peopleID); + + return Response.ok(newPet).build(); + } catch (IllegalArgumentException iae) { + LOG.log(Level.FINE, "Invalid pet id in add method", iae); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(iae.getMessage()) + .build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error adding a pet", e); + + return Response.serverError() + .entity(e.getMessage()) + .build(); + } + } + + @PUT + @Path("/{id}") + public Response modify( + @PathParam("id") int id, + @FormParam("name") String name, + @FormParam("peopleID") int peopleID + ) { + try { + final Pet modifiedPet = new Pet(id, name, peopleID); + this.dao.modify(modifiedPet); + + return Response.ok(modifiedPet).build(); + } catch (NullPointerException npe) { + final String message = String.format("Invalid data for person (name: %s, peopleID: %s)", name, peopleID); + + LOG.log(Level.FINE, message); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(message) + .build(); + } catch (IllegalArgumentException iae) { + LOG.log(Level.FINE, "Invalid pet id in modify method", iae); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(iae.getMessage()) + .build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error modifying a pet", e); + + return Response.serverError() + .entity(e.getMessage()) + .build(); + } + } + + @DELETE + @Path("/{id}") + public Response delete( + @PathParam("id") int id + ) { + try { + this.dao.delete(id); + + return Response.ok(id).build(); + } catch (IllegalArgumentException iae) { + LOG.log(Level.FINE, "Invalid pet id in delete method", iae); + + return Response.status(Response.Status.BAD_REQUEST) + .entity(iae.getMessage()) + .build(); + } catch (DAOException e) { + LOG.log(Level.SEVERE, "Error deleting a pet", e); + + return Response.serverError() + .entity(e.getMessage()) + .build(); + } + } +} diff --git a/src/main/webapp/js/dao/people.js b/src/main/webapp/js/dao/people.js index 29618ee..793da29 100644 --- a/src/main/webapp/js/dao/people.js +++ b/src/main/webapp/js/dao/people.js @@ -1,5 +1,6 @@ var PeopleDAO = (function() { var resourcePath = "rest/people/"; + var petsPath = "rest/pets/"; var requestByAjax = function(data, done, fail, always) { done = typeof done !== 'undefined' ? done : function() {}; fail = typeof fail !== 'undefined' ? fail : function() {}; @@ -23,6 +24,17 @@ var PeopleDAO = (function() { }, done, fail, always); }; + this.listPetsByPeopleID = function(id, name, done, fail, always) { + $.ajax({ + url : petsPath + "people" + id, + type : 'GET' + }).done(function() { + localStorage.setItem('peopleID', btoa(id)); + localStorage.setItem('peopleName', name); + window.location = 'pets.html'; + }); + }; + this.addPerson = function(person, done, fail, always) { requestByAjax({ url : resourcePath, diff --git a/src/main/webapp/js/dao/pets.js b/src/main/webapp/js/dao/pets.js new file mode 100644 index 0000000..4b51fd2 --- /dev/null +++ b/src/main/webapp/js/dao/pets.js @@ -0,0 +1,52 @@ +var PetDAO = (function() { + var resourcePath = "rest/pets/"; + var peopleID = atob(localStorage.getItem('peopleID')); + var requestByAjax = function(data, done, fail, always) { + done = typeof done !== 'undefined' ? done : function() {}; + fail = typeof fail !== 'undefined' ? fail : function() {}; + always = typeof always !== 'undefined' ? always : function() {}; + + let authToken = localStorage.getItem('authorization-token'); + if (authToken !== null) { + data.beforeSend = function(xhr) { + xhr.setRequestHeader('Authorization', 'Basic ' + authToken); + }; + } + + $.ajax(data).done(done).fail(fail).always(always); + }; + + function PetDAO() { + this.listPetsByPeopleID = function(done, fail, always) { + requestByAjax({ + url : resourcePath + 'people' + peopleID, + type : 'GET' + }, done, fail, always); + }; + + this.addPet = function(pet, done, fail, always) { + requestByAjax({ + url : resourcePath, + type : 'POST', + data : pet + }, done, fail, always); + }; + + this.modifyPet = function(pet, done, fail, always) { + requestByAjax({ + url : resourcePath + pet.id, + type : 'PUT', + data : pet + }, done, fail, always); + }; + + this.deletePet = function(id, done, fail, always) { + requestByAjax({ + url : resourcePath + id, + type : 'DELETE', + }, done, fail, always); + }; + } + + return PetDAO; +})(); \ No newline at end of file diff --git a/src/main/webapp/js/view/people.js b/src/main/webapp/js/view/people.js index 802d6b2..904a85f 100644 --- a/src/main/webapp/js/view/people.js +++ b/src/main/webapp/js/view/people.js @@ -106,6 +106,10 @@ var PeopleView = (function() { } }; + this.listPetsByPeopleID = function(id, name) { + dao.listPetsByPeopleID(id, name, showErrorMessage); + }; + this.isEditing = function() { return $(formQuery + ' input[name="id"]').val() != ""; }; @@ -132,7 +136,7 @@ var PeopleView = (function() { \ Nombre\ Apellido\ -  \ + Acciones\ \ \ \ @@ -166,6 +170,7 @@ var PeopleView = (function() { ' + person.name + '\ ' + person.surname + '\ \ + Mascotas\ Editar\ Eliminar\ \ @@ -184,6 +189,10 @@ var PeopleView = (function() { $('#person-' + person.id + ' a.delete').click(function() { self.deletePerson(person.id); }); + + $('#person-' + person.id + ' a.pets').click(function() { + self.listPetsByPeopleID(person.id, person.name); + }); }; var appendToTable = function(person) { diff --git a/src/main/webapp/js/view/pets.js b/src/main/webapp/js/view/pets.js new file mode 100644 index 0000000..ac6ff7f --- /dev/null +++ b/src/main/webapp/js/view/pets.js @@ -0,0 +1,197 @@ +var PetView = (function() { + var dao; + + // Referencia a this que permite acceder a las funciones públicas desde las funciones de jQuery. + var self; + var peopleID; + var peopleName; + + var formId = 'pets-form'; + var listId = 'pets-list'; + var formQuery = '#' + formId; + var listQuery = '#' + listId; + + function PetView(petDao, formContainerId, listContainerId) { + dao = petDao; + self = this; + peopleID = atob(localStorage.getItem('peopleID')); + peopleName = localStorage.getItem('peopleName'); + document.getElementById('name').innerHTML = peopleName; + + insertPetForm($('#' + formContainerId)); + insertPetList($('#' + listContainerId)); + + this.init = function() { + dao.listPetsByPeopleID(function(pets) { + $.each(pets, function(key, pet) { + appendToTable(pet); + }); + }, + function() { + alert('No has sido posible acceder al listado de mascotas.'); + }); + + // La acción por defecto de enviar formulario (submit) se sobreescribe + // para que el envío sea a través de AJAX + $(formQuery).submit(function(event) { + var pet = self.getPetInForm(); + + if (self.isEditing()) { + dao.modifyPet(pet, + function(pet) { + $('#pet-' + pet.id + ' td.name').text(pet.name); + $('#pet-' + pet.id + ' td.peopleID').text(peopleID); + self.resetForm(); + }, + showErrorMessage, + self.enableForm + ); + } else { + dao.addPet(pet, + function(pet) { + appendToTable(pet); + self.resetForm(); + }, + showErrorMessage, + self.enableForm + ); + } + + return false; + }); + + $('#btnClear').click(this.resetForm); + }; + + this.getPetInForm = function() { + var form = $(formQuery); + return { + 'id': form.find('input[name="id"]').val(), + 'name': form.find('input[name="name"]').val(), + 'peopleID': peopleID + }; + }; + + this.getPetInRow = function(id) { + var row = $('#pet-' + id); + + if (row !== undefined) { + return { + 'id': id, + 'name': row.find('td.name').text(), + 'peopleID': peopleID + }; + } else { + return undefined; + } + }; + + this.editPet = function(id) { + var row = $('#pet-' + id); + + if (row !== undefined) { + var form = $(formQuery); + + form.find('input[name="id"]').val(id); + form.find('input[name="name"]').val(row.find('td.name').text()); + form.find('input[name="peopleID"]').val(peopleID); + + $('input#btnSubmit').val('Modificar'); + } + }; + + this.deletePet = function(id) { + if (confirm('Está a punto de eliminar a una pet. ¿Está seguro de que desea continuar?')) { + dao.deletePet(id, + function() { + $('tr#pet-' + id).remove(); + }, + showErrorMessage + ); + } + }; + + this.isEditing = function() { + return $(formQuery + ' input[name="id"]').val() != ""; + }; + + this.disableForm = function() { + $(formQuery + ' input').prop('disabled', true); + }; + + this.enableForm = function() { + $(formQuery + ' input').prop('disabled', false); + }; + + this.resetForm = function() { + $(formQuery)[0].reset(); + $(formQuery + ' input[name="id"]').val(''); + $('#btnSubmit').val('Crear'); + }; + }; + + var insertPetList = function(parent) { + parent.append( + '\ + \ + \ + \ + \ + \ + \ + \ + \ +
NombreAcciones
' + ); + }; + + var insertPetForm = function(parent) { + parent.append( + '
\ + \ + \ +
\ +
\ + \ +
\ +
\ + \ + \ +
\ +
\ +
' + ); + }; + + var createPetRow = function(pet) { + return '\ + ' + pet.name + '\ + \ + Editar\ + Eliminar\ + \ + '; + }; + + var showErrorMessage = function(jqxhr, textStatus, error) { + alert(textStatus + ": " + error); + }; + + var addRowListeners = function(pet) { + $('#pet-' + pet.id + ' a.edit').click(function() { + self.editPet(pet.id); + }); + + $('#pet-' + pet.id + ' a.delete').click(function() { + self.deletePet(pet.id); + }); + }; + + var appendToTable = function(pet) { + $(listQuery + ' > tbody:last') + .append(createPetRow(pet)); + addRowListeners(pet); + }; + + return PetView; +})(); \ No newline at end of file diff --git a/src/main/webapp/pets.html b/src/main/webapp/pets.html new file mode 100644 index 0000000..1d7db7b --- /dev/null +++ b/src/main/webapp/pets.html @@ -0,0 +1,50 @@ + + + + + +DAA Example + + + + +
+ +
+ +
+
+

Mascotas de

+
+
+ + + + + + + + \ No newline at end of file -- 2.18.1