From 76e57a6a3560e73af206488d1c4d2ff68800d55a Mon Sep 17 00:00:00 2001 From: Shreyas Prayag Date: Tue, 20 May 2025 18:53:57 +0530 Subject: [PATCH] added functionality to get and update a pet --- pom.xml | 13 +++ .../samples/petclinic/owner/NewPet.java | 101 ++++++++++++++++++ .../petclinic/owner/NewPetController.java | 92 ++++++++++++++++ .../petclinic/owner/NewPetRepository.java | 33 ++++++ .../petclinic/owner/PetTemperament.java | 46 ++++++++ src/main/resources/application.properties | 14 ++- 6 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/springframework/samples/petclinic/owner/NewPet.java create mode 100644 src/main/java/org/springframework/samples/petclinic/owner/NewPetController.java create mode 100644 src/main/java/org/springframework/samples/petclinic/owner/NewPetRepository.java create mode 100644 src/main/java/org/springframework/samples/petclinic/owner/PetTemperament.java diff --git a/pom.xml b/pom.xml index 27fb9a6bd..a6b166c93 100644 --- a/pom.xml +++ b/pom.xml @@ -152,6 +152,19 @@ jakarta.xml.bind-api + + org.projectlombok + lombok + + + org.projectlombok + lombok + provided + + + org.springframework.boot + spring-boot-starter-hateoas + diff --git a/src/main/java/org/springframework/samples/petclinic/owner/NewPet.java b/src/main/java/org/springframework/samples/petclinic/owner/NewPet.java new file mode 100644 index 000000000..3a8dc4fa9 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/owner/NewPet.java @@ -0,0 +1,101 @@ +package org.springframework.samples.petclinic.owner; + +import jakarta.annotation.Nonnull; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder + +/** + * Simple business object representing a pet. + * + * @author Shreyas Prayag + */ + +public class NewPet { + + /** + * The unique identifier for the pet. This field is mapped to the "id" column in the + * "new_pet" table. It is automatically generated by the database when a new pet is + * created. + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + /** + * The name of the pet. This field is mapped to the "name" column in the "new_pet" + * table. It cannot be null and should not be empty. + */ + @NotNull + private String name; + + /** + * The date of birth of the pet. This field is mapped to the "birth_date" column in + * the "new_pet" table. It cannot be null and should not be empty. + */ + private Date birthDate; + + /** + * The owner of the pet. + *

+ * This field represents a many-to-one relationship between pets and their owners — + * each pet is associated with one owner, but an owner can have multiple pets. + *

+ *

+ * The relationship is mapped via the {@code owner_id} foreign key in the + * {@code new_pet} table. + *

+ * + * @see Owner + */ + @ManyToOne + @JoinColumn(name = "owner_id") + private Owner owner; + + /** + * The temperament of the pet. + *

+ * This field represents a many-to-one relationship between pets and their + * temperaments — each pet has one temperament, there can be more than one pets with + * one temperament. + *

+ *

+ * The relationship is mapped via the {@code temperament_id} foreign key in the + * {@code new_pet} table. + *

+ * + * @see PetTemperament + */ + @ManyToOne() + @JoinColumn(name = "temperament_id") + private PetTemperament temperament; + + /** + * The type of the pet. + *

+ * This field represents a many-to-one relationship between pets and their owners — + * each pet is associated with one type, but there can be multiple pets of a type. + *

+ *

+ * The relationship is mapped via the {@code type_id} foreign key in the + * {@code new_pet} table. + *

+ * + * @see Owner + */ + @ManyToOne + @JoinColumn(name = "type_id") + private PetType type; + +} diff --git a/src/main/java/org/springframework/samples/petclinic/owner/NewPetController.java b/src/main/java/org/springframework/samples/petclinic/owner/NewPetController.java new file mode 100644 index 000000000..11a2e9544 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/owner/NewPetController.java @@ -0,0 +1,92 @@ +package org.springframework.samples.petclinic.owner; + +import org.springframework.hateoas.EntityModel; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; + +/** + * new Controller to handle requests relating pet + * + * The existing controller is not a REST API controller. So this controller is created to + * cater Rest endpoints relating Pet. + * + * @author Shreyas Prayag + * @since 1.0 + */ +@RestController +@RequestMapping("owners/{ownerId}") +public class NewPetController { + + private final NewPetRepository petRepository; + + NewPetController(NewPetRepository petRepository) { + this.petRepository = petRepository; + } + + /** + * Retrieves a pet by its ID. + *

+ * This endpoint returns a pet based on the provided pet ID. If the pet with the given + * ID exists, it returns the pet details in the response body with a 200 OK status. If + * the pet is not found, a 404 Not Found status is returned. + *

+ * @param petId The ID of the pet to retrieve. It is expected to be a positive + * integer. + * @return A {@link ResponseEntity} containing the {@link Pet} object if found, or a + * 404 response if not found. + * + * this endpoint is hateoas compliant + */ + @GetMapping("/pet/{petId}") + public ResponseEntity> getPetById(@PathVariable int ownerId, @PathVariable int petId) { + + NewPet pet = petRepository.findById(petId); + + if (pet == null) { + return ResponseEntity.notFound().build(); + } + + EntityModel petResource = EntityModel.of(pet); + + // Add self link + petResource.add(linkTo(methodOn(NewPetController.class).getPetById(ownerId, petId)).withSelfRel()); + + // Add link to create new pet + petResource.add(linkTo(methodOn(NewPetController.class).createNewPet(ownerId, null)).withRel("create-new-pet")); + + return ResponseEntity.ok(petResource); + + } + + /** + * Creates a new pet. + *

+ * This endpoint accepts a {@link Pet} object in the request body and saves it to the + * database. It returns the created {@link Pet} object along with a 201 Created HTTP + * status code. If the pet data is invalid, a 400 Bad Request status is returned. + *

+ * @param newPet The pet object to create. This is expected to contain the pet details + * in the request body. + * @return A {@link ResponseEntity} containing the created {@link Pet} object and a + * 201 Created status. + * + * this endpoint is hateoas compliant + */ + @PostMapping("/pet") + public ResponseEntity> createNewPet(@PathVariable int ownerId, @RequestBody NewPet newPet) { + + NewPet savedPet = petRepository.save(newPet); + EntityModel petResource = EntityModel.of(savedPet); + + // Add self link + petResource.add(linkTo(methodOn(NewPetController.class).getPetById(ownerId, savedPet.getId())).withSelfRel()); + + return ResponseEntity.status(HttpStatus.CREATED).body(petResource); + + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/owner/NewPetRepository.java b/src/main/java/org/springframework/samples/petclinic/owner/NewPetRepository.java new file mode 100644 index 000000000..0e0b0db35 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/owner/NewPetRepository.java @@ -0,0 +1,33 @@ +package org.springframework.samples.petclinic.owner; + +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * Repository interface for managing {@link NewPet} entities. + *

+ * Extends {@link JpaRepository} to provide CRUD operations, pagination, and JPA-specific + * functionality. + *

+ * + * @author You + * @since 1.0 + */ +public interface NewPetRepository extends JpaRepository { + + /** + * Finds the pet with the given id. + * @param id The id of the pet to search for. + * @return a pet with the specified id. + * + */ + NewPet findById(int id); + + /** + * Saves the given pet + * @param newPet The pet object to be saved. + * @return pet object being saved. + * + */ + NewPet save(NewPet newPet); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/owner/PetTemperament.java b/src/main/java/org/springframework/samples/petclinic/owner/PetTemperament.java new file mode 100644 index 000000000..ece2657bd --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/owner/PetTemperament.java @@ -0,0 +1,46 @@ +package org.springframework.samples.petclinic.owner; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder + +/** + * Simple business object representing pet temperament. + * + * @author Shreyas Prayag + */ +public class PetTemperament { + + /** + * The unique identifier for the temperament. This field is mapped to the "id" column + * in the "pet_temperament" table. It is automatically generated by the database when + * a new temperament is created. + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + /** + * The Temperament of pet. This field is mapped to the "temperament" column in the + * "pet_temperament" table. It cannot be null and should not be empty. + */ + @NotNull + private String temperament; + + public PetTemperament(String temperament) { + this.temperament = temperament; + } + +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6ed985654..5a64972cf 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,13 +1,23 @@ # database init, supports mysql too -database=h2 +database=mysql spring.sql.init.schema-locations=classpath*:db/${database}/schema.sql spring.sql.init.data-locations=classpath*:db/${database}/data.sql + +# Data Source properties +spring.datasource.url=jdbc:mysql://localhost:3306/petclinic +spring.datasource.username=petclinic +spring.datasource.password=petclinic +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +# Logging level for Hibernate SQL +logging.level.org.hibernate.SQL=DEBUG # Web spring.thymeleaf.mode=HTML # JPA -spring.jpa.hibernate.ddl-auto=none +spring.jpa.hibernate.ddl-auto=update +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect spring.jpa.open-in-view=false # Internationalization