diff --git a/eureka/persons-server/pom.xml b/eureka/persons-server/pom.xml index b342d8e..0f0f141 100644 --- a/eureka/persons-server/pom.xml +++ b/eureka/persons-server/pom.xml @@ -70,6 +70,48 @@ org.projectlombok lombok + + org.springframework + spring-tx + + + org.springframework + spring-tx + 5.3.15 + + + org.springframework.data + spring-data-jpa + 2.6.1 + + + org.springframework.data + spring-data-commons + 2.6.1 + + + org.hibernate.javax.persistence + hibernate-jpa-2.1-api + 2.2 + + + org.hibernate + hibernate-core + 6.0.0.Alpha6 + + + org.assertj + assertj-core + + + org.hibernate + hibernate-core + 5.2.12.Final + + + net.bytebuddy + byte-buddy + diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/PersonsController.java b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsController.java index ff4acb5..ba2f625 100644 --- a/eureka/persons-server/src/main/java/com/eureka/persons/PersonsController.java +++ b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsController.java @@ -1,5 +1,7 @@ package com.eureka.persons; +import com.eureka.persons.base.AbstractEntity; +import com.eureka.persons.ex.NotFoundException; import com.eureka.persons.person.Person; import com.eureka.persons.services.PersonService; import org.springframework.http.HttpStatus; @@ -7,8 +9,9 @@ import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import java.util.Optional; @RestController @RequestMapping("/persons") @@ -26,7 +29,10 @@ public PersonsController(PersonService personService) { @ResponseStatus(HttpStatus.OK) @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public List list() { - return new ArrayList<>(); + List people = personService.findAll(); + people.sort(Comparator.comparing(AbstractEntity::getId)); + + return people; } /** @@ -36,6 +42,11 @@ public List list() { @ResponseStatus(HttpStatus.CREATED) @PostMapping public void create(@RequestBody Person person, BindingResult result) { + if (result.hasErrors()) { + throw new PersonsException(HttpStatus.BAD_REQUEST, "Person could not be created!"); + } + + personService.save(person); } /** @@ -48,7 +59,7 @@ public void create(@RequestBody Person person, BindingResult result) { @ResponseStatus(HttpStatus.OK) @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) public Person show(@PathVariable Long id) { - return new Person(); + return personService.findById(id).orElseThrow(() -> new NotFoundException(Person.class, id)); } /** @@ -62,6 +73,16 @@ public Person show(@PathVariable Long id) { @ResponseStatus(HttpStatus.NO_CONTENT) @PutMapping("/{id}") public void update(@RequestBody Person updatedPerson, @PathVariable Long id) { + Person person = show(id); + + person.setUsername(updatedPerson.getUsername()); + person.setFirstName(updatedPerson.getFirstName()); + person.setLastName(updatedPerson.getLastName()); + person.setPassword(updatedPerson.getPassword()); + person.setHiringDate(updatedPerson.getHiringDate()); + person.setNewPassword(updatedPerson.getNewPassword()); + + personService.save(person); } /** @@ -73,5 +94,7 @@ public void update(@RequestBody Person updatedPerson, @PathVariable Long id) { @ResponseStatus(HttpStatus.NO_CONTENT) @DeleteMapping("/{id}") public void delete(@PathVariable Long id) { + Person person = show(id); + personService.delete(person); } } \ No newline at end of file diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/PersonsServer.java b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsServer.java index f2098ae..c23be15 100644 --- a/eureka/persons-server/src/main/java/com/eureka/persons/PersonsServer.java +++ b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsServer.java @@ -5,11 +5,13 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import java.io.IOException; @EntityScan(basePackages = "com.eureka.persons") @SpringBootApplication +@EnableEurekaClient public class PersonsServer { private static Logger logger = LoggerFactory.getLogger(PersonsServer.class); diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/base/AbstractEntity.java b/eureka/persons-server/src/main/java/com/eureka/persons/base/AbstractEntity.java index 199103b..448a274 100644 --- a/eureka/persons-server/src/main/java/com/eureka/persons/base/AbstractEntity.java +++ b/eureka/persons-server/src/main/java/com/eureka/persons/base/AbstractEntity.java @@ -1,17 +1,25 @@ package com.eureka.persons.base; -import com.eureka.persons.util.DateProcessor; -import com.fasterxml.jackson.annotation.JsonFormat; -import lombok.Getter; -import lombok.Setter; -import org.springframework.format.annotation.DateTimeFormat; - -import javax.persistence.*; import java.io.Serializable; import java.time.LocalDateTime; import java.util.Comparator; import java.util.Objects; +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.persistence.Version; + +import org.springframework.format.annotation.DateTimeFormat; + +import com.eureka.persons.util.DateProcessor; +import com.fasterxml.jackson.annotation.JsonFormat; + +import lombok.Getter; +import lombok.Setter; + @MappedSuperclass @Getter @Setter @@ -24,6 +32,14 @@ public abstract class AbstractEntity implements Serializable { @Column(updatable = false) protected Long id; + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + @Version protected int version; diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/person/Person.java b/eureka/persons-server/src/main/java/com/eureka/persons/person/Person.java index 9064df8..b06b109 100644 --- a/eureka/persons-server/src/main/java/com/eureka/persons/person/Person.java +++ b/eureka/persons-server/src/main/java/com/eureka/persons/person/Person.java @@ -23,7 +23,8 @@ @Setter @NoArgsConstructor public class Person extends AbstractEntity { - interface BasicValidation{} + interface BasicValidation { + } @NotNull(groups = BasicValidation.class) @Size(min = 3, max = 30, groups = BasicValidation.class) @@ -77,6 +78,54 @@ public String toString() { return String.format("Person[username='%s', firstName='%s', lastName='%s', hiringDate='%s']\n", username, firstName, lastName, hiringDate.toString()); + + } + + public String getUsername() { + return username; } -} + public void setUsername(String username) { + this.username = username; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public LocalDateTime getHiringDate() { + return hiringDate; + } + + public void setHiringDate(LocalDateTime hiringDate) { + this.hiringDate = hiringDate; + } + + public String getNewPassword() { + return newPassword; + } + + public void setNewPassword(String newPassword) { + this.newPassword = newPassword; + } +} \ No newline at end of file diff --git a/eureka/persons-server/src/main/resources/persons-server.yml b/eureka/persons-server/src/main/resources/persons-server.yml index b2b466d..ae83478 100644 --- a/eureka/persons-server/src/main/resources/persons-server.yml +++ b/eureka/persons-server/src/main/resources/persons-server.yml @@ -25,6 +25,11 @@ server: # Discovery Server Access #TODO here you add configurations for eureka client +eureka: + client: + serviceUrl: + defaultZone: http://localhost:3000/eureka/ + fetchRegistry: true info: app: diff --git a/lab-6-api-gateway/api-gateway-project/src/main/resources/application.yml b/lab-6-api-gateway/api-gateway-project/src/main/resources/application.yml index aaad35d..40c14f3 100644 --- a/lab-6-api-gateway/api-gateway-project/src/main/resources/application.yml +++ b/lab-6-api-gateway/api-gateway-project/src/main/resources/application.yml @@ -1,5 +1,31 @@ server: port: 8080 + address: 0.0.0.0 + + eureka: + client: + serviceUrl: + defaultZone: http://localhost:3000/eureka/ + register-with-eureka: true + fetch-registry: true + + spring: + application: + name: gateway + main: + web-application-type: reactive + cloud: + gateway: + routes: + - id: service1 + uri: http://localhost:8081 + predicates: + - Path=/api/greeting/** + - id: service2 + uri: http://localhost:8082 + predicates: + - Path=/product/** + #TODO use eureka to discover the URL for the service1 and service2 #TODO configure spring cloud gateway to route the request to downstream services (service1 and service2) based on the paths(/api/greeting, /product) #TODO for greeting endpoint add a route to accept requests to /greeting but before calling service1 it must append api before the greeting path (HINT: rewrite path filter) diff --git a/lab-6-api-gateway/service1/pom.xml b/lab-6-api-gateway/service1/pom.xml index 478fe3f..22377d7 100644 --- a/lab-6-api-gateway/service1/pom.xml +++ b/lab-6-api-gateway/service1/pom.xml @@ -18,10 +18,10 @@ 2021.0.1 - + org.springframework.boot spring-boot-starter-actuator @@ -30,24 +30,27 @@ org.springframework.boot spring-boot-starter-web - + + org.springframework.cloud + spring-cloud-netflix-eureka-client + org.springframework.boot spring-boot-starter-test test - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + diff --git a/lab-6-api-gateway/service1/src/main/java/com/example/service1/Service1Application.java b/lab-6-api-gateway/service1/src/main/java/com/example/service1/Service1Application.java index 27128b5..ae276e7 100644 --- a/lab-6-api-gateway/service1/src/main/java/com/example/service1/Service1Application.java +++ b/lab-6-api-gateway/service1/src/main/java/com/example/service1/Service1Application.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +@EnableEurekaClient @SpringBootApplication public class Service1Application { diff --git a/lab-6-api-gateway/service1/src/main/java/com/example/service1/controller/Service1Controller.java b/lab-6-api-gateway/service1/src/main/java/com/example/service1/controller/Service1Controller.java new file mode 100644 index 0000000..b93cf1f --- /dev/null +++ b/lab-6-api-gateway/service1/src/main/java/com/example/service1/controller/Service1Controller.java @@ -0,0 +1,21 @@ +package com.example.service1.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@RestController +@RequestMapping("/api") +public class Service1Controller { + + @ResponseStatus(HttpStatus.OK) + @GetMapping(value = "/greeting/{name}") + public String greeting(@PathVariable String name, @RequestHeader Map headers) { + System.out.println("Headers:"); + for (Map.Entry header : headers.entrySet()) { + System.out.println(header); + } + return String.format("Hello, %s!", name); + } +} diff --git a/lab-6-api-gateway/service1/src/main/resources/application.yml b/lab-6-api-gateway/service1/src/main/resources/application.yml index 54b155f..7b37856 100644 --- a/lab-6-api-gateway/service1/src/main/resources/application.yml +++ b/lab-6-api-gateway/service1/src/main/resources/application.yml @@ -1,2 +1,14 @@ server: - port: 8081 \ No newline at end of file + port: 8081 + address: 0.0.0.0 + + spring: + application: + name: service1 + + eureka: + client: + serviceUrl: + defaultZone: http://localhost:3000/eureka/ + register-with-eureka: true + fetch-registry: true \ No newline at end of file diff --git a/lab-6-api-gateway/service2/pom.xml b/lab-6-api-gateway/service2/pom.xml index be06918..a3e7960 100644 --- a/lab-6-api-gateway/service2/pom.xml +++ b/lab-6-api-gateway/service2/pom.xml @@ -26,16 +26,32 @@ org.springframework.boot spring-boot-starter-web - + org.springframework.boot spring-boot-starter-test test + + org.springframework.cloud + spring-cloud-netflix-eureka-client + + + org.hibernate + hibernate-core + + + org.projectlombok + lombok + + + org.projectlombok + lombok + diff --git a/lab-6-api-gateway/service2/src/main/java/com/example/service2/Service2Application.java b/lab-6-api-gateway/service2/src/main/java/com/example/service2/Service2Application.java index 3c2fbd2..b87df25 100644 --- a/lab-6-api-gateway/service2/src/main/java/com/example/service2/Service2Application.java +++ b/lab-6-api-gateway/service2/src/main/java/com/example/service2/Service2Application.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +@EnableEurekaClient @SpringBootApplication public class Service2Application { diff --git a/lab-6-api-gateway/service2/src/main/java/com/example/service2/controller/Service2Controller.java b/lab-6-api-gateway/service2/src/main/java/com/example/service2/controller/Service2Controller.java new file mode 100644 index 0000000..ea9bc8f --- /dev/null +++ b/lab-6-api-gateway/service2/src/main/java/com/example/service2/controller/Service2Controller.java @@ -0,0 +1,34 @@ +package com.example.service2.controller; + +import com.example.service2.model.Product; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/product") +public class Service2Controller { + private List products = new ArrayList(); + + @PostMapping() + @ResponseStatus(HttpStatus.OK) + public void addProduct(@RequestBody Product product, @RequestHeader Map headers) { + for (Map.Entry header : headers.entrySet()) { + System.out.println(header); + } + products.add(product); + } + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(HttpStatus.OK) + public List getProducts(@RequestHeader Map headers) { + for (Map.Entry header : headers.entrySet()) { + System.out.println(header); + } + return products; + } +} diff --git a/lab-6-api-gateway/service2/src/main/java/com/example/service2/model/Product.java b/lab-6-api-gateway/service2/src/main/java/com/example/service2/model/Product.java new file mode 100644 index 0000000..c19f296 --- /dev/null +++ b/lab-6-api-gateway/service2/src/main/java/com/example/service2/model/Product.java @@ -0,0 +1,24 @@ +package com.example.service2.model; + +import com.sun.istack.NotNull; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Column; +import javax.persistence.Entity; + +@Entity +@Getter +@Setter +@NoArgsConstructor +public class Product { + + @NotNull + @Column(nullable = false, unique = true) + private String name; + + @NotNull + @Column(nullable = false, unique = true) + private int quantity; +} \ No newline at end of file diff --git a/lab-6-api-gateway/service2/src/main/resources/application.yml b/lab-6-api-gateway/service2/src/main/resources/application.yml index 4772153..41d64e3 100644 --- a/lab-6-api-gateway/service2/src/main/resources/application.yml +++ b/lab-6-api-gateway/service2/src/main/resources/application.yml @@ -1,3 +1,14 @@ - server: - port: 8082 \ No newline at end of file + port: 8082 + address: 0.0.0.0 + + spring: + application: + name: service2 + + eureka: + client: + serviceUrl: + defaultZone: http://localhost:3000/eureka/ + register-with-eureka: true + fetch-registry: true \ No newline at end of file diff --git a/recipe/HELP.md b/recipe/HELP.md new file mode 100644 index 0000000..e0690dd --- /dev/null +++ b/recipe/HELP.md @@ -0,0 +1,9 @@ +# Getting Started + +### Reference Documentation +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.6.5/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.6.5/maven-plugin/reference/html/#build-image) + diff --git a/recipe/target/classes/application.properties b/recipe/target/classes/application.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/recipe/target/classes/application.properties @@ -0,0 +1 @@ + diff --git a/spring2/target/classes/application.properties b/spring2/target/classes/application.properties new file mode 100644 index 0000000..a8d8dfc --- /dev/null +++ b/spring2/target/classes/application.properties @@ -0,0 +1 @@ +car.model=Audi \ No newline at end of file diff --git a/spring2/target/classes/profiles.properties b/spring2/target/classes/profiles.properties new file mode 100644 index 0000000..eedfad6 --- /dev/null +++ b/spring2/target/classes/profiles.properties @@ -0,0 +1 @@ +spring.profiles.active=DEV \ No newline at end of file