diff --git a/README.md b/README.md index 416e8910c..a226b1027 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) This microservices branch was initially derived from [AngularJS version](https://github.com/spring-petclinic/spring-petclinic-angular1) to demonstrate how to split sample Spring application into [microservices](http://www.martinfowler.com/articles/microservices.html). -To achieve that goal we use Spring Cloud Gateway, Spring Cloud Circuit Breaker, Spring Cloud Config, Spring Cloud Sleuth, Resilience4j, Micrometer +To achieve that goal, we use Spring Cloud Gateway, Spring Cloud Circuit Breaker, Spring Cloud Config, Spring Cloud Sleuth, Resilience4j, Micrometer and the Eureka Service Discovery from the [Spring Cloud Netflix](https://github.com/spring-cloud/spring-cloud-netflix) technology stack. ## Starting services locally without Docker @@ -29,7 +29,7 @@ You can tell Config Server to use your local Git repository by using `native` Sp In order to start entire infrastructure using Docker, you have to build images by executing `./mvnw clean install -P buildDocker` from a project root. Once images are ready, you can start them with a single command `docker-compose up`. Containers startup order is coordinated with [`dockerize` script](https://github.com/jwilder/dockerize). -After starting services it takes a while for API Gateway to be in sync with service registry, +After starting services, it takes a while for API Gateway to be in sync with service registry, so don't be scared of initial Spring Cloud Gateway timeouts. You can track services availability using Eureka dashboard available by default at http://localhost:8761. @@ -48,7 +48,7 @@ Each of the java based applications is started with the `chaos-monkey` profile i [See the presentation of the Spring Petclinic Framework version](http://fr.slideshare.net/AntoineRey/spring-framework-petclinic-sample-application) -[A blog bost introducing the Spring Petclinic Microsevices](http://javaetmoi.com/2018/10/architecture-microservices-avec-spring-cloud/) (french language) +[A blog post introducing the Spring Petclinic Microsevices](http://javaetmoi.com/2018/10/architecture-microservices-avec-spring-cloud/) (french language) You can then access petclinic here: http://localhost:8080/ diff --git a/spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/CustomersServiceClient.java b/spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/CustomersServiceClient.java index e0619b1dc..691254e00 100644 --- a/spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/CustomersServiceClient.java +++ b/spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/CustomersServiceClient.java @@ -18,7 +18,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.samples.petclinic.api.dto.OwnerDetails; import org.springframework.stereotype.Component; -import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; diff --git a/spring-petclinic-api-gateway/src/main/resources/static/scripts/owner-form/owner-form.template.html b/spring-petclinic-api-gateway/src/main/resources/static/scripts/owner-form/owner-form.template.html index 0d49cfb92..17e97a3f2 100644 --- a/spring-petclinic-api-gateway/src/main/resources/static/scripts/owner-form/owner-form.template.html +++ b/spring-petclinic-api-gateway/src/main/resources/static/scripts/owner-form/owner-form.template.html @@ -27,7 +27,8 @@

Owner

- + Telephone is required.
diff --git a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/Owner.java b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/Owner.java index 542919668..88860faa4 100644 --- a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/Owner.java +++ b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/Owner.java @@ -31,8 +31,10 @@ import javax.persistence.OneToMany; import javax.persistence.Table; import javax.validation.constraints.Digits; -import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.Setter; import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.PropertyComparator; import org.springframework.core.style.ToStringCreator; @@ -45,6 +47,7 @@ * @author Sam Brannen * @author Michael Isvy * @author Maciej Szarlinski + * @author Ramazan Sakin */ @Entity @Table(name = "owners") @@ -52,76 +55,43 @@ public class Owner { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Getter private Integer id; + @Getter + @Setter @Column(name = "first_name") - @NotEmpty + @NotBlank private String firstName; + @Getter + @Setter @Column(name = "last_name") - @NotEmpty + @NotBlank private String lastName; + @Getter + @Setter @Column(name = "address") - @NotEmpty + @NotBlank private String address; + @Getter + @Setter @Column(name = "city") - @NotEmpty + @NotBlank private String city; + @Getter + @Setter @Column(name = "telephone") - @NotEmpty - @Digits(fraction = 0, integer = 10) + @NotBlank + @Digits(fraction = 0, integer = 12) private String telephone; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "owner") private Set pets; - public Integer getId() { - return id; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(final String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(final String lastName) { - this.lastName = lastName; - } - - public String getAddress() { - return this.address; - } - - public void setAddress(String address) { - this.address = address; - } - - public String getCity() { - return this.city; - } - - public void setCity(String city) { - this.city = city; - } - - public String getTelephone() { - return this.telephone; - } - - public void setTelephone(String telephone) { - this.telephone = telephone; - } - protected Set getPetsInternal() { if (this.pets == null) { this.pets = new HashSet<>(); diff --git a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/Pet.java b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/Pet.java index 0dc3ca770..b89924f0d 100644 --- a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/Pet.java +++ b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/Pet.java @@ -29,6 +29,7 @@ import javax.persistence.TemporalType; import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; import org.springframework.core.style.ToStringCreator; /** @@ -38,7 +39,9 @@ * @author Juergen Hoeller * @author Sam Brannen * @author Maciej Szarlinski + * @author Ramazan Sakin */ +@Data @Entity @Table(name = "pets") public class Pet { @@ -62,46 +65,6 @@ public class Pet { @JsonIgnore private Owner owner; - public Integer getId() { - return id; - } - - public void setId(final Integer id) { - this.id = id; - } - - public String getName() { - return this.name; - } - - public void setName(final String name) { - this.name = name; - } - - public Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(final Date birthDate) { - this.birthDate = birthDate; - } - - public PetType getType() { - return type; - } - - public void setType(final PetType type) { - this.type = type; - } - - public Owner getOwner() { - return owner; - } - - public void setOwner(final Owner owner) { - this.owner = owner; - } - @Override public String toString() { return new ToStringCreator(this) diff --git a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/PetType.java b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/PetType.java index fcac8596c..3a7162fda 100644 --- a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/PetType.java +++ b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/model/PetType.java @@ -15,6 +15,9 @@ */ package org.springframework.samples.petclinic.customers.model; +import lombok.Getter; +import lombok.Setter; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -24,27 +27,21 @@ /** * @author Juergen Hoeller + * @author Ramazan Sakin * Can be Cat, Dog, Hamster... */ @Entity @Table(name = "types") public class PetType { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Getter + @Setter private Integer id; + @Getter + @Setter @Column(name = "name") private String name; - - public Integer getId() { - return id; - } - - public void setId(final Integer id) { - this.id = id; - } - - public String getName() { - return this.name; - } } diff --git a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java index cc830db7c..b867f1aa2 100644 --- a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java +++ b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java @@ -24,6 +24,7 @@ import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +import javax.validation.constraints.Min; import java.util.List; import java.util.Optional; @@ -56,7 +57,7 @@ public Owner createOwner(@Valid @RequestBody Owner owner) { * Read single Owner */ @GetMapping(value = "/{ownerId}") - public Optional findOwner(@PathVariable("ownerId") int ownerId) { + public Optional findOwner(@PathVariable("ownerId") @Min(1) int ownerId) { return ownerRepository.findById(ownerId); } @@ -73,10 +74,10 @@ public List findAll() { */ @PutMapping(value = "/{ownerId}") @ResponseStatus(HttpStatus.NO_CONTENT) - public void updateOwner(@PathVariable("ownerId") int ownerId, @Valid @RequestBody Owner ownerRequest) { + public void updateOwner(@PathVariable("ownerId") @Min(1) int ownerId, @Valid @RequestBody Owner ownerRequest) { final Optional owner = ownerRepository.findById(ownerId); - final Owner ownerModel = owner.orElseThrow(() -> new ResourceNotFoundException("Owner "+ownerId+" not found")); + // This is done by hand for simplicity purpose. In a real life use-case we should consider using MapStruct. ownerModel.setFirstName(ownerRequest.getFirstName()); ownerModel.setLastName(ownerRequest.getLastName()); diff --git a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/PetResource.java b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/PetResource.java index 62245d2e6..7ec597a4b 100644 --- a/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/PetResource.java +++ b/spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/PetResource.java @@ -22,6 +22,7 @@ import org.springframework.samples.petclinic.customers.model.*; import org.springframework.web.bind.annotation.*; +import javax.validation.constraints.Min; import java.util.List; import java.util.Optional; @@ -30,6 +31,7 @@ * @author Ken Krebs * @author Arjen Poutsma * @author Maciej Szarlinski + * @author Ramazan Sakin */ @RestController @Timed("petclinic.pet") @@ -50,13 +52,13 @@ public List getPetTypes() { @ResponseStatus(HttpStatus.CREATED) public Pet processCreationForm( @RequestBody PetRequest petRequest, - @PathVariable("ownerId") int ownerId) { + @PathVariable("ownerId") @Min(1) int ownerId) { - final Pet pet = new Pet(); final Optional optionalOwner = ownerRepository.findById(ownerId); Owner owner = optionalOwner.orElseThrow(() -> new ResourceNotFoundException("Owner "+ownerId+" not found")); - owner.addPet(pet); + final Pet pet = new Pet(); + owner.addPet(pet); return save(pet, petRequest); } diff --git a/spring-petclinic-customers-service/src/main/resources/db/hsqldb/schema.sql b/spring-petclinic-customers-service/src/main/resources/db/hsqldb/schema.sql index 9aa6666bf..33d42ee5a 100644 --- a/spring-petclinic-customers-service/src/main/resources/db/hsqldb/schema.sql +++ b/spring-petclinic-customers-service/src/main/resources/db/hsqldb/schema.sql @@ -14,7 +14,7 @@ CREATE TABLE owners ( last_name VARCHAR(30), address VARCHAR(255), city VARCHAR(80), - telephone VARCHAR(20) + telephone VARCHAR(12) ); CREATE INDEX owners_last_name ON owners (last_name); diff --git a/spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/model/Specialty.java b/spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/model/Specialty.java index e0267d062..c5c0869c6 100644 --- a/spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/model/Specialty.java +++ b/spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/model/Specialty.java @@ -15,6 +15,9 @@ */ package org.springframework.samples.petclinic.vets.model; +import lombok.Getter; +import lombok.Setter; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -26,30 +29,20 @@ * Models a {@link Vet Vet's} specialty (for example, dentistry). * * @author Juergen Hoeller + * @author Ramazan Sakin */ + @Entity @Table(name = "specialties") public class Specialty { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Getter private Integer id; + @Getter + @Setter @Column(name = "name") private String name; - public Integer getId() { - return id; - } - - public void setId(final Integer id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(final String name) { - this.name = name; - } } diff --git a/spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/model/Vet.java b/spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/model/Vet.java index 31135eccb..4976a39bc 100644 --- a/spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/model/Vet.java +++ b/spring-petclinic-vets-service/src/main/java/org/springframework/samples/petclinic/vets/model/Vet.java @@ -31,9 +31,11 @@ import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; -import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotBlank; import javax.xml.bind.annotation.XmlElement; +import lombok.Getter; +import lombok.Setter; import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.PropertyComparator; @@ -45,6 +47,7 @@ * @author Sam Brannen * @author Arjen Poutsma * @author Maciej Szarlinski + * @author Ramazan Sakin */ @Entity @Table(name = "vets") @@ -52,14 +55,20 @@ public class Vet { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Getter + @Setter private Integer id; @Column(name = "first_name") - @NotEmpty + @NotBlank + @Getter + @Setter private String firstName; @Column(name = "last_name") - @NotEmpty + @NotBlank + @Getter + @Setter private String lastName; @ManyToMany(fetch = FetchType.EAGER) @@ -67,30 +76,6 @@ public class Vet { inverseJoinColumns = @JoinColumn(name = "specialty_id")) private Set specialties; - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public String getFirstName() { - return this.firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return this.lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - protected Set getSpecialtiesInternal() { if (this.specialties == null) { this.specialties = new HashSet<>(); diff --git a/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/model/Visit.java b/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/model/Visit.java index c7032140f..deede8eed 100644 --- a/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/model/Visit.java +++ b/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/model/Visit.java @@ -16,7 +16,11 @@ package org.springframework.samples.petclinic.visits.model; import com.fasterxml.jackson.annotation.JsonFormat; -import java.util.Date; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -26,19 +30,19 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.validation.constraints.Size; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.NoArgsConstructor; +import java.util.Date; /** * Simple JavaBean domain object representing a visit. * * @author Ken Krebs * @author Maciej Szarlinski + * @author Ramazan Sakin */ @Entity @Table(name = "visits") @Builder(builderMethodName = "visit") +@Data @NoArgsConstructor @AllArgsConstructor public class Visit { @@ -60,24 +64,4 @@ public class Visit { @Column(name = "pet_id") private int petId; - public Integer getId() { - return id; - } - - public Date getDate() { - return date; - } - - public String getDescription() { - return description; - } - - public int getPetId() { - return petId; - } - - public void setPetId(final int petId) { - this.petId = petId; - } - } diff --git a/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java b/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java index 0f1e391b4..ab940b5bc 100644 --- a/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java +++ b/spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java @@ -17,6 +17,7 @@ import java.util.List; import javax.validation.Valid; +import javax.validation.constraints.Min; import io.micrometer.core.annotation.Timed; import lombok.RequiredArgsConstructor; @@ -39,6 +40,7 @@ * @author Arjen Poutsma * @author Michael Isvy * @author Maciej Szarlinski + * @author Ramazan Sakin */ @RestController @RequiredArgsConstructor @@ -50,9 +52,9 @@ class VisitResource { @PostMapping("owners/*/pets/{petId}/visits") @ResponseStatus(HttpStatus.CREATED) - public Visit create( + public Visit create( @Valid @RequestBody Visit visit, - @PathVariable("petId") int petId) { + @PathVariable("petId") @Min(1) int petId) { visit.setPetId(petId); log.info("Saving visit {}", visit); @@ -60,12 +62,12 @@ public Visit create( } @GetMapping("owners/*/pets/{petId}/visits") - public List visits(@PathVariable("petId") int petId) { + public List visits(@PathVariable("petId") @Min(1) int petId) { return visitRepository.findByPetId(petId); } @GetMapping("pets/visits") - public Visits visitsMultiGet(@RequestParam("petId") List petIds) { + public Visits visitsMultiGet(@RequestParam("petId") List petIds) { final List byPetIdIn = visitRepository.findByPetIdIn(petIds); return new Visits(byPetIdIn); }