added vaccine apis and delete apis

This commit is contained in:
chetan deore 2025-07-18 21:48:17 +05:30
parent 30aab0ae76
commit 4e5db56cd6
17 changed files with 286 additions and 15 deletions

13
pom.xml
View file

@ -145,6 +145,19 @@
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

View file

@ -0,0 +1,29 @@
package org.springframework.samples.petclinic.api.controller;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.api.service.OwnerService;
import org.springframework.samples.petclinic.owner.Owner;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController("owner-controller")
@RestControllerAdvice
@Validated
@RequestMapping("/api/owner")
public class OwnerHistoryController {
@Autowired
private OwnerService ownerService;
@PostMapping
public void addOwner(@Valid @RequestBody Owner owner) {
ownerService.addOwner(owner);
}
@GetMapping
public String getOwner() {
return "API working";
}
}

View file

@ -0,0 +1,16 @@
package org.springframework.samples.petclinic.api.service;
import org.springframework.samples.petclinic.owner.Owner;
import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.stereotype.Service;
@Service
public class OwnerService {
private OwnerRepository ownerRepository;
public void addOwner(Owner owner) {
ownerRepository.save(owner);
}
}

View file

@ -0,0 +1,8 @@
package org.springframework.samples.petclinic.exception;
public class NotFoundException extends RuntimeException{
public NotFoundException(String message){
super(message);
}
}

View file

@ -18,6 +18,7 @@ package org.springframework.samples.petclinic.owner;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
import org.springframework.core.style.ToStringCreator;
import org.springframework.samples.petclinic.model.Person;
import org.springframework.util.Assert;
@ -60,6 +61,8 @@ public class Owner extends Person {
@Pattern(regexp = "\\d{10}", message = "{telephone.invalid}")
private String telephone;
private Boolean active;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
@OrderBy("name")
@ -93,6 +96,14 @@ public class Owner extends Person {
return this.pets;
}
public Boolean isActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
public void addPet(Pet pet) {
if (pet.isNew()) {
getPets().add(pet);

View file

@ -18,24 +18,23 @@ package org.springframework.samples.petclinic.owner;
import java.util.List;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.samples.petclinic.exception.NotFoundException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import jakarta.validation.Valid;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import static java.lang.String.format;
/**
* @author Juergen Hoeller
* @author Ken Krebs
@ -43,7 +42,9 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
* @author Michael Isvy
* @author Wick Dynex
*/
@Controller
@RestController
@Slf4j
@RequestMapping
class OwnerController {
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
@ -170,4 +171,17 @@ class OwnerController {
return mav;
}
@DeleteMapping("owners/{ownerId}")
public void deleteOwner(@PathVariable("ownerId") int id,
@RequestParam(name = "deletePets", required = false, defaultValue = "false") boolean deletePets){
var owner = this.owners.findById(id)
.orElseThrow(() -> new NotFoundException(format("owner not found with id %s", id)));
owner.setActive(Boolean.FALSE);
if(deletePets){
owner.getPets()
.forEach(pet -> pet.setActive(Boolean.FALSE));
}
owners.save(owner);
log.info("Owner {} marked inactive{}", id, deletePets ? " along with pets" : "");
}
}

View file

@ -62,4 +62,6 @@ public interface OwnerRepository extends JpaRepository<Owner, Integer> {
*/
Optional<Owner> findById(@Nonnull Integer id);
Optional<Owner> findByIdAndActive(@Nonnull Integer id, Boolean active);
}

View file

@ -17,6 +17,7 @@ package org.springframework.samples.petclinic.owner;
import java.time.LocalDate;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
@ -32,6 +33,7 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OrderBy;
import jakarta.persistence.Table;
import org.springframework.samples.petclinic.vaccine.Vaccination;
/**
* Simple business object representing a pet.
@ -53,11 +55,16 @@ public class Pet extends NamedEntity {
@JoinColumn(name = "type_id")
private PetType type;
private Boolean active;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "pet_id")
@OrderBy("date ASC")
private final Set<Visit> visits = new LinkedHashSet<>();
@OneToMany(mappedBy = "pet", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Vaccination> vaccinations = new LinkedHashSet<>();
public void setBirthDate(LocalDate birthDate) {
this.birthDate = birthDate;
}
@ -82,4 +89,16 @@ public class Pet extends NamedEntity {
getVisits().add(visit);
}
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
public void addVaccination(Vaccination vaccination) {
vaccination.setPet(this);
this.vaccinations.add(vaccination);
}
}

View file

@ -0,0 +1,23 @@
package org.springframework.samples.petclinic.vaccine;
import jakarta.persistence.*;
import lombok.Data;
import org.springframework.samples.petclinic.owner.Pet;
import java.time.LocalDate;
@Entity
@Data
public class Vaccination {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String vaccineName;
private LocalDate vaccinationDate;
private String description;
private Boolean injected;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pet_id", nullable = false)
private Pet pet;
}

View file

@ -0,0 +1,21 @@
package org.springframework.samples.petclinic.vaccine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.samples.petclinic.owner.PetTypeRepository;
import org.springframework.samples.petclinic.vaccine.request.VaccinationRequest;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/vaccine")
public class VaccinationController {
private VaccinationService vaccinationService;
@PostMapping("/owner/{owner_id}/pet/{petId}")
public void addVaccine(@PathVariable Integer owner_id, @PathVariable Long petId,
@RequestBody VaccinationRequest request){
vaccinationService.addVaccineToPet(owner_id, petId, request);
}
}

View file

@ -0,0 +1,8 @@
package org.springframework.samples.petclinic.vaccine;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface VaccinationRepository extends JpaRepository<Vaccination, Long> {
}

View file

@ -0,0 +1,46 @@
package org.springframework.samples.petclinic.vaccine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.exception.NotFoundException;
import org.springframework.samples.petclinic.owner.OwnerRepository;
import org.springframework.samples.petclinic.owner.Pet;
import org.springframework.samples.petclinic.vaccine.predicate.PetPredicates;
import org.springframework.samples.petclinic.vaccine.request.VaccinationRequest;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static java.lang.String.format;
@Service
public class VaccinationService {
@Autowired
private VaccinationRepository vaccinationRepository;
private OwnerRepository ownerRepository;
public void addVaccineToPet(Integer ownerId, Long petId, VaccinationRequest request) {
var owner = ownerRepository.findByIdAndActive(ownerId, Boolean.TRUE)
.orElseThrow(()-> new NotFoundException(format("owner not found with id %s", ownerId)));
var pet = owner.getPets().stream()
.filter(PetPredicates.isActive().and(PetPredicates.hasId(petId)))
.findFirst()
.orElseThrow(() -> new NotFoundException(format("Active pet not found with id %s", petId)));;
Vaccination vaccination = new Vaccination();
vaccination.setPet(pet);
vaccination.setVaccineName("Vacine1");
vaccination.setDescription("Need to inject");
vaccination.setVaccinationDate(request.getVaccinationDate());
pet.addVaccination(vaccination);
vaccinationRepository.save(vaccination);
}
}

View file

@ -0,0 +1,16 @@
package org.springframework.samples.petclinic.vaccine.predicate;
import org.springframework.samples.petclinic.owner.Pet;
import java.util.function.Predicate;
public class PetPredicates {
public static Predicate<Pet> isActive() {
return pet -> Boolean.TRUE.equals(pet.getActive());
}
public static Predicate<Pet> hasId(Long petId) {
return pet -> petId.equals(pet.getId());
}
}

View file

@ -0,0 +1,18 @@
package org.springframework.samples.petclinic.vaccine.request;
import jakarta.annotation.Nonnull;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.time.LocalDate;
@Data
@Valid
public class VaccinationRequest {
@NotBlank
private String vaccineName;
private LocalDate vaccinationDate;
@NotBlank
private String description;
}

View file

@ -1,7 +1,11 @@
# database init, supports postgres too
database=postgres
spring.datasource.url=${POSTGRES_URL:jdbc:postgresql://localhost/petclinic}
spring.datasource.username=${POSTGRES_USER:petclinic}
spring.datasource.password=${POSTGRES_PASS:petclinic}
database=petclinic
#spring.datasource.url=${POSTGRES_URL:jdbc:postgresql://localhost/petclinic}
spring.datasource.url=jdbc:postgresql://localhost:5432/petclinic
spring.datasource.username=postgres
spring.datasource.password=root
#spring.datasource.username=${POSTGRES_USER:petclinic}
#spring.datasource.password=${POSTGRES_PASS:petclinic}
# SQL is written to be idempotent so this is safe
spring.sql.init.mode=always

View file

@ -1,14 +1,19 @@
# database init, supports mysql too
database=h2
spring.sql.init.schema-locations=classpath*:db/${database}/schema.sql
spring.sql.init.data-locations=classpath*:db/${database}/data.sql
database=postgres
spring.sql.init.schema-locations=classpath*:db/postgres/schema.sql,classpath*:db/postgres/alter.sql
spring.sql.init.data-locations=classpath*:db/postgres/data.sql
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.springframework.jdbc.datasource.init=DEBUG
# Web
spring.thymeleaf.mode=HTML
# JPA
spring.jpa.hibernate.ddl-auto=none
spring.jpa.open-in-view=false
spring.jpa.open-in-view=true
# Internationalization
spring.messages.basename=messages/messages
@ -23,3 +28,5 @@ logging.level.org.springframework=INFO
# Maximum time static resources should be cached
spring.web.resources.cache.cachecontrol.max-age=12h

View file

@ -0,0 +1,16 @@
ALTER TABLE owners ADD COLUMN IF NOT EXISTS active BOOLEAN DEFAULT TRUE;
ALTER TABLE pets ADD COLUMN IF NOT EXISTS active BOOLEAN DEFAULT TRUE;
CREATE TABLE IF NOT EXISTS vaccinations (
id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
vaccine_name TEXT NOT NULL,
vaccination_date DATE NOT NULL,
description TEXT,
injected BOOLEAN DEFAULT FALSE,
pet_id BIGINT NOT NULL,
CONSTRAINT fk_pet
FOREIGN KEY (pet_id)
REFERENCES pets(id)
ON DELETE CASCADE
);