├── .gitignore ├── department-service ├── .gitignore ├── nbactions.xml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── py │ │ │ └── department │ │ │ ├── DepartmentApplication.java │ │ │ ├── client │ │ │ └── EmployeeClient.java │ │ │ ├── controller │ │ │ └── DepartmentController.java │ │ │ ├── model │ │ │ ├── Department.java │ │ │ └── Employee.java │ │ │ └── repository │ │ │ └── DepartmentRepository.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── DepartmentRepositoryTest.java ├── discovery-service ├── .gitignore ├── nb-configuration.xml ├── nbactions.xml ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── py │ │ └── discovery │ │ └── DiscoveryApplication.java │ └── resources │ └── application.yml ├── employee-service ├── .gitignore ├── nbactions.xml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── py │ │ │ └── employee │ │ │ ├── EmployeeApplication.java │ │ │ ├── controller │ │ │ └── EmployeeController.java │ │ │ ├── model │ │ │ └── Employee.java │ │ │ └── repository │ │ │ └── EmployeeRepository.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── pl │ └── piomin │ └── services │ └── employee │ └── EmployeeRepositoryTest.java ├── gateway-service ├── .gitignore ├── nbactions.xml ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── py │ │ └── gateway │ │ └── GatewayApplication.java │ └── resources │ └── application.yml ├── organization-service ├── .gitignore ├── nbactions.xml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── py │ │ │ └── organization │ │ │ ├── OrganizationApplication.java │ │ │ ├── client │ │ │ ├── DepartmentClient.java │ │ │ └── EmployeeClient.java │ │ │ ├── controller │ │ │ └── OrganizationController.java │ │ │ ├── model │ │ │ ├── Department.java │ │ │ ├── Employee.java │ │ │ └── Organization.java │ │ │ └── repository │ │ │ └── OrganizationRepository.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── OrganizationRepositoryTest.java ├── pom.xml └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | /.project 2 | /.settings/ 3 | -------------------------------------------------------------------------------- /department-service/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.classpath 3 | /.project 4 | /.settings/ 5 | -------------------------------------------------------------------------------- /department-service/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 11 | 12 | 13 | 14 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 15 | 16 | com.py.department.DepartmentApplication 17 | java 18 | 19 | 20 | 21 | debug 22 | 23 | jar 24 | 25 | 26 | process-classes 27 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 28 | 29 | 30 | -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} 31 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 32 | 33 | com.py.department.DepartmentApplication 34 | java 35 | true 36 | 37 | 38 | 39 | profile 40 | 41 | jar 42 | 43 | 44 | process-classes 45 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 46 | 47 | 48 | 49 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 50 | com.py.department.DepartmentApplication 51 | java 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /department-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.springframework.boot 5 | spring-boot-starter-parent 6 | 2.6.1 7 | 8 | 9 | department-service 10 | com.py 11 | 1.2-SNAPSHOT 12 | 13 | 14 | 17 15 | 2021.0.0 16 | 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-dependencies 23 | ${spring-cloud.version} 24 | pom 25 | import 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-netflix-eureka-client 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-openfeign 38 | 39 | 40 | org.springframework.cloud 41 | spring-cloud-openfeign-core 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-web 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-actuator 50 | 51 | 52 | org.springframework.cloud 53 | spring-cloud-starter-sleuth 54 | 55 | 56 | org.springdoc 57 | springdoc-openapi-webmvc-core 58 | 1.5.13 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-starter-test 63 | test 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.springframework.boot 71 | spring-boot-maven-plugin 72 | 73 | 74 | org.jacoco 75 | jacoco-maven-plugin 76 | 0.8.7 77 | 78 | 79 | 80 | prepare-agent 81 | 82 | 83 | 84 | report 85 | test 86 | 87 | report 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /department-service/src/main/java/com/py/department/DepartmentApplication.java: -------------------------------------------------------------------------------- 1 | package com.py.department; 2 | 3 | import io.swagger.v3.oas.annotations.OpenAPIDefinition; 4 | import io.swagger.v3.oas.annotations.info.Info; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.cloud.openfeign.EnableFeignClients; 8 | import org.springframework.context.annotation.Bean; 9 | import com.py.department.model.Department; 10 | import com.py.department.repository.DepartmentRepository; 11 | 12 | @SpringBootApplication 13 | @EnableFeignClients 14 | @OpenAPIDefinition(info = 15 | @Info(title = "Department API", version = "1.0", description = "Documentation Department API v1.0") 16 | ) 17 | public class DepartmentApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(DepartmentApplication.class, args); 21 | } 22 | 23 | @Bean 24 | DepartmentRepository repository() { 25 | DepartmentRepository repository = new DepartmentRepository(); 26 | repository.add(new Department(1L, "Development")); 27 | repository.add(new Department(1L, "Operations")); 28 | repository.add(new Department(2L, "Development")); 29 | repository.add(new Department(2L, "Operations")); 30 | return repository; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /department-service/src/main/java/com/py/department/client/EmployeeClient.java: -------------------------------------------------------------------------------- 1 | package com.py.department.client; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.cloud.openfeign.FeignClient; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | 9 | import com.py.department.model.Employee; 10 | 11 | @FeignClient(name = "employee-service") 12 | public interface EmployeeClient { 13 | 14 | @GetMapping("/department/{departmentId}") 15 | List findByDepartment(@PathVariable("departmentId") Long departmentId); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /department-service/src/main/java/com/py/department/controller/DepartmentController.java: -------------------------------------------------------------------------------- 1 | package com.py.department.controller; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.web.bind.annotation.*; 6 | import com.py.department.client.EmployeeClient; 7 | import com.py.department.model.Department; 8 | import com.py.department.repository.DepartmentRepository; 9 | 10 | import java.util.List; 11 | 12 | @RestController 13 | public class DepartmentController { 14 | 15 | private static final Logger LOGGER = LoggerFactory.getLogger(DepartmentController.class); 16 | 17 | DepartmentRepository repository; 18 | EmployeeClient employeeClient; 19 | 20 | public DepartmentController(DepartmentRepository repository, EmployeeClient employeeClient) { 21 | this.repository = repository; 22 | this.employeeClient = employeeClient; 23 | } 24 | 25 | @PostMapping("/") 26 | public Department add(@RequestBody Department department) { 27 | LOGGER.info("Department add: {}", department); 28 | return repository.add(department); 29 | } 30 | 31 | @GetMapping("/{id}") 32 | public Department findById(@PathVariable("id") Long id) { 33 | LOGGER.info("Department find: id={}", id); 34 | return repository.findById(id); 35 | } 36 | 37 | @GetMapping("/") 38 | public List findAll() { 39 | LOGGER.info("Department find"); 40 | return repository.findAll(); 41 | } 42 | 43 | @GetMapping("/organization/{organizationId}") 44 | public List findByOrganization(@PathVariable("organizationId") Long organizationId) { 45 | LOGGER.info("Department find: organizationId={}", organizationId); 46 | return repository.findByOrganization(organizationId); 47 | } 48 | 49 | @GetMapping("/organization/{organizationId}/with-employees") 50 | public List findByOrganizationWithEmployees(@PathVariable("organizationId") Long organizationId) { 51 | LOGGER.info("Department find: organizationId={}", organizationId); 52 | List departments = repository.findByOrganization(organizationId); 53 | departments.forEach(d -> d.setEmployees(employeeClient.findByDepartment(d.getId()))); 54 | return departments; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /department-service/src/main/java/com/py/department/model/Department.java: -------------------------------------------------------------------------------- 1 | package com.py.department.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Department { 7 | 8 | private Long id; 9 | private Long organizationId; 10 | private String name; 11 | private List employees = new ArrayList<>(); 12 | 13 | public Department() { 14 | 15 | } 16 | 17 | public Department(Long organizationId, String name) { 18 | super(); 19 | this.organizationId = organizationId; 20 | this.name = name; 21 | } 22 | 23 | public Long getId() { 24 | return id; 25 | } 26 | 27 | public void setId(Long id) { 28 | this.id = id; 29 | } 30 | 31 | public Long getOrganizationId() { 32 | return organizationId; 33 | } 34 | 35 | public void setOrganizationId(Long organizationId) { 36 | this.organizationId = organizationId; 37 | } 38 | 39 | public String getName() { 40 | return name; 41 | } 42 | 43 | public void setName(String name) { 44 | this.name = name; 45 | } 46 | 47 | public List getEmployees() { 48 | return employees; 49 | } 50 | 51 | public void setEmployees(List employees) { 52 | this.employees = employees; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "Department [id=" + id + ", organizationId=" + organizationId + ", name=" + name + "]"; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /department-service/src/main/java/com/py/department/model/Employee.java: -------------------------------------------------------------------------------- 1 | package com.py.department.model; 2 | 3 | public class Employee { 4 | 5 | private Long id; 6 | private String name; 7 | private int age; 8 | private String position; 9 | 10 | public Employee() { 11 | 12 | } 13 | 14 | public Employee(String name, int age, String position) { 15 | this.name = name; 16 | this.age = age; 17 | this.position = position; 18 | } 19 | 20 | public Long getId() { 21 | return id; 22 | } 23 | 24 | public void setId(Long id) { 25 | this.id = id; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public void setName(String name) { 33 | this.name = name; 34 | } 35 | 36 | public int getAge() { 37 | return age; 38 | } 39 | 40 | public void setAge(int age) { 41 | this.age = age; 42 | } 43 | 44 | public String getPosition() { 45 | return position; 46 | } 47 | 48 | public void setPosition(String position) { 49 | this.position = position; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "Employee [id=" + id + ", name=" + name + ", position=" + position + "]"; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /department-service/src/main/java/com/py/department/repository/DepartmentRepository.java: -------------------------------------------------------------------------------- 1 | package com.py.department.repository; 2 | 3 | import com.py.department.model.Department; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class DepartmentRepository { 9 | 10 | private List departments = new ArrayList<>(); 11 | 12 | public Department add(Department department) { 13 | department.setId((long) (departments.size()+1)); 14 | departments.add(department); 15 | return department; 16 | } 17 | 18 | public Department findById(Long id) { 19 | return departments.stream() 20 | .filter(a -> a.getId().equals(id)) 21 | .findFirst() 22 | .orElseThrow(); 23 | } 24 | 25 | public List findAll() { 26 | return departments; 27 | } 28 | 29 | public List findByOrganization(Long organizationId) { 30 | return departments.stream() 31 | .filter(a -> a.getOrganizationId().equals(organizationId)) 32 | .toList(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /department-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: department-service 4 | 5 | server: 6 | port: 0 7 | 8 | eureka: 9 | client: 10 | serviceUrl: 11 | defaultZone: http://localhost:8061/eureka/ 12 | 13 | logging: 14 | pattern: 15 | console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n" 16 | 17 | springdoc: 18 | packagesToScan: com.py.department -------------------------------------------------------------------------------- /department-service/src/test/java/DepartmentRepositoryTest.java: -------------------------------------------------------------------------------- 1 | import org.junit.jupiter.api.MethodOrderer; 2 | import org.junit.jupiter.api.Order; 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.TestMethodOrder; 5 | import org.springframework.util.Assert; 6 | import com.py.department.model.Department; 7 | import com.py.department.repository.DepartmentRepository; 8 | 9 | import java.util.List; 10 | 11 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 12 | public class DepartmentRepositoryTest { 13 | 14 | private static final DepartmentRepository repository = new DepartmentRepository(); 15 | 16 | @Test 17 | @Order(1) 18 | void testAddDepartment() { 19 | Department department = new Department(1L, "Test"); 20 | department = repository.add(department); 21 | Assert.notNull(department, "Department is null."); 22 | Assert.isTrue(department.getId() == 1L, "Department bad id."); 23 | } 24 | 25 | @Test 26 | @Order(2) 27 | void testFindAll() { 28 | List departments = repository.findAll(); 29 | Assert.isTrue(departments.size() == 1, "Departments size is wrong."); 30 | Assert.isTrue(departments.get(0).getId() == 1L, "Department bad id."); 31 | } 32 | 33 | @Test 34 | @Order(3) 35 | void testFindByOrganization() { 36 | List departments = repository.findByOrganization(1L); 37 | Assert.isTrue(departments.size() == 1, "Departments size is wrong."); 38 | Assert.isTrue(departments.get(0).getId() == 1L, "Department bad id."); 39 | } 40 | 41 | @Test 42 | @Order(4) 43 | void testFindById() { 44 | Department department = repository.findById(1L); 45 | Assert.notNull(department, "Department not found."); 46 | Assert.isTrue(department.getId() == 1L, "Department bad id."); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /discovery-service/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.settings/ 3 | /.classpath 4 | /.project 5 | -------------------------------------------------------------------------------- /discovery-service/nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | true 17 | 18 | 19 | -------------------------------------------------------------------------------- /discovery-service/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 11 | 12 | 13 | 14 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 15 | 16 | com.py.discovery.DiscoveryApplication 17 | java 18 | 19 | 20 | 21 | debug 22 | 23 | jar 24 | 25 | 26 | process-classes 27 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 28 | 29 | 30 | -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} 31 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 32 | 33 | com.py.discovery.DiscoveryApplication 34 | java 35 | true 36 | 37 | 38 | 39 | profile 40 | 41 | jar 42 | 43 | 44 | process-classes 45 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 46 | 47 | 48 | 49 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 50 | com.py.discovery.DiscoveryApplication 51 | java 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /discovery-service/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.springframework.boot 6 | spring-boot-starter-parent 7 | 2.6.1 8 | 9 | 10 | discovery-service 11 | com.py 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 17 16 | 2021.0.0 17 | 18 | 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-dependencies 24 | ${spring-cloud.version} 25 | pom 26 | import 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.cloud 34 | spring-cloud-starter-netflix-eureka-server 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-maven-plugin 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /discovery-service/src/main/java/com/py/discovery/DiscoveryApplication.java: -------------------------------------------------------------------------------- 1 | package com.py.discovery; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | import org.springframework.boot.builder.SpringApplicationBuilder; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class DiscoveryApplication { 10 | 11 | public static void main(String[] args) { 12 | new SpringApplicationBuilder(DiscoveryApplication.class).run(args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /discovery-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: discovery-service 4 | 5 | server: 6 | port: 8061 7 | 8 | eureka: 9 | instance: 10 | hostname: localhost 11 | client: 12 | registerWithEureka: false 13 | fetchRegistry: false 14 | serviceUrl: 15 | defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ -------------------------------------------------------------------------------- /employee-service/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.classpath 3 | /.project 4 | /.settings/ 5 | -------------------------------------------------------------------------------- /employee-service/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 11 | 12 | 13 | 14 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 15 | 16 | com.py.employee.EmployeeApplication 17 | java 18 | 19 | 20 | 21 | debug 22 | 23 | jar 24 | 25 | 26 | process-classes 27 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 28 | 29 | 30 | -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} 31 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 32 | 33 | com.py.employee.EmployeeApplication 34 | java 35 | true 36 | 37 | 38 | 39 | profile 40 | 41 | jar 42 | 43 | 44 | process-classes 45 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 46 | 47 | 48 | 49 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 50 | com.py.employee.EmployeeApplication 51 | java 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /employee-service/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.springframework.boot 6 | spring-boot-starter-parent 7 | 2.6.1 8 | 9 | 10 | employee-service 11 | com.py 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 17 16 | 2021.0.0 17 | 18 | 19 | 20 | 21 | 22 | org.springframework.cloud 23 | spring-cloud-dependencies 24 | ${spring-cloud.version} 25 | pom 26 | import 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.cloud 34 | spring-cloud-starter-netflix-eureka-client 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-actuator 43 | 44 | 45 | org.springframework.cloud 46 | spring-cloud-starter-sleuth 47 | 48 | 49 | org.springdoc 50 | springdoc-openapi-webmvc-core 51 | 1.5.13 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter-test 56 | test 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | org.jacoco 68 | jacoco-maven-plugin 69 | 0.8.7 70 | 71 | 72 | 73 | prepare-agent 74 | 75 | 76 | 77 | report 78 | test 79 | 80 | report 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /employee-service/src/main/java/com/py/employee/EmployeeApplication.java: -------------------------------------------------------------------------------- 1 | package com.py.employee; 2 | 3 | import io.swagger.v3.oas.annotations.OpenAPIDefinition; 4 | import io.swagger.v3.oas.annotations.info.Info; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.annotation.Bean; 8 | import com.py.employee.model.Employee; 9 | import com.py.employee.repository.EmployeeRepository; 10 | 11 | @SpringBootApplication 12 | @OpenAPIDefinition(info = 13 | @Info(title = "Employee API", version = "1.0", description = "Documentation Employee API v1.0") 14 | ) 15 | public class EmployeeApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(EmployeeApplication.class, args); 19 | } 20 | 21 | @Bean 22 | EmployeeRepository repository() { 23 | EmployeeRepository repository = new EmployeeRepository(); 24 | repository.add(new Employee(1L, 1L, "John Smith", 34, "Analyst")); 25 | repository.add(new Employee(1L, 1L, "Darren Hamilton", 37, "Manager")); 26 | repository.add(new Employee(1L, 1L, "Tom Scott", 26, "Developer")); 27 | repository.add(new Employee(1L, 2L, "Anna London", 39, "Analyst")); 28 | repository.add(new Employee(1L, 2L, "Patrick Dempsey", 27, "Developer")); 29 | repository.add(new Employee(2L, 3L, "Kevin Price", 38, "Developer")); 30 | repository.add(new Employee(2L, 3L, "Ian Scott", 34, "Developer")); 31 | repository.add(new Employee(2L, 3L, "Andrew Campton", 30, "Manager")); 32 | repository.add(new Employee(2L, 4L, "Steve Franklin", 25, "Developer")); 33 | repository.add(new Employee(2L, 4L, "Elisabeth Smith", 30, "Developer")); 34 | return repository; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /employee-service/src/main/java/com/py/employee/controller/EmployeeController.java: -------------------------------------------------------------------------------- 1 | package com.py.employee.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import com.py.employee.model.Employee; 15 | import com.py.employee.repository.EmployeeRepository; 16 | 17 | @RestController 18 | public class EmployeeController { 19 | 20 | private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeController.class); 21 | 22 | @Autowired 23 | EmployeeRepository repository; 24 | 25 | @PostMapping("/") 26 | public Employee add(@RequestBody Employee employee) { 27 | LOGGER.info("Employee add: {}", employee); 28 | return repository.add(employee); 29 | } 30 | 31 | @GetMapping("/{id}") 32 | public Employee findById(@PathVariable("id") Long id) { 33 | LOGGER.info("Employee find: id={}", id); 34 | return repository.findById(id); 35 | } 36 | 37 | @GetMapping("/") 38 | public List findAll() { 39 | LOGGER.info("Employee find"); 40 | return repository.findAll(); 41 | } 42 | 43 | @GetMapping("/department/{departmentId}") 44 | public List findByDepartment(@PathVariable("departmentId") Long departmentId) { 45 | LOGGER.info("Employee find: departmentId={}", departmentId); 46 | return repository.findByDepartment(departmentId); 47 | } 48 | 49 | @GetMapping("/organization/{organizationId}") 50 | public List findByOrganization(@PathVariable("organizationId") Long organizationId) { 51 | LOGGER.info("Employee find: organizationId={}", organizationId); 52 | return repository.findByOrganization(organizationId); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /employee-service/src/main/java/com/py/employee/model/Employee.java: -------------------------------------------------------------------------------- 1 | package com.py.employee.model; 2 | 3 | public class Employee { 4 | 5 | private Long id; 6 | private Long organizationId; 7 | private Long departmentId; 8 | private String name; 9 | private int age; 10 | private String position; 11 | 12 | public Employee() { 13 | 14 | } 15 | 16 | public Employee(Long organizationId, Long departmentId, String name, int age, String position) { 17 | this.organizationId = organizationId; 18 | this.departmentId = departmentId; 19 | this.name = name; 20 | this.age = age; 21 | this.position = position; 22 | } 23 | 24 | public Long getId() { 25 | return id; 26 | } 27 | 28 | public void setId(Long id) { 29 | this.id = id; 30 | } 31 | 32 | public Long getOrganizationId() { 33 | return organizationId; 34 | } 35 | 36 | public void setOrganizationId(Long organizationId) { 37 | this.organizationId = organizationId; 38 | } 39 | 40 | public Long getDepartmentId() { 41 | return departmentId; 42 | } 43 | 44 | public void setDepartmentId(Long departmentId) { 45 | this.departmentId = departmentId; 46 | } 47 | 48 | public String getName() { 49 | return name; 50 | } 51 | 52 | public void setName(String name) { 53 | this.name = name; 54 | } 55 | 56 | public int getAge() { 57 | return age; 58 | } 59 | 60 | public void setAge(int age) { 61 | this.age = age; 62 | } 63 | 64 | public String getPosition() { 65 | return position; 66 | } 67 | 68 | public void setPosition(String position) { 69 | this.position = position; 70 | } 71 | 72 | @Override 73 | public String toString() { 74 | return "Employee [id=" + id + ", organizationId=" + organizationId + ", departmentId=" + departmentId 75 | + ", name=" + name + ", position=" + position + "]"; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /employee-service/src/main/java/com/py/employee/repository/EmployeeRepository.java: -------------------------------------------------------------------------------- 1 | package com.py.employee.repository; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import java.util.stream.Collectors; 7 | 8 | import com.py.employee.model.Employee; 9 | 10 | public class EmployeeRepository { 11 | 12 | private List employees = new ArrayList<>(); 13 | 14 | public Employee add(Employee employee) { 15 | employee.setId((long) (employees.size()+1)); 16 | employees.add(employee); 17 | return employee; 18 | } 19 | 20 | public Employee findById(Long id) { 21 | return employees.stream() 22 | .filter(a -> a.getId().equals(id)) 23 | .findFirst() 24 | .orElseThrow(); 25 | } 26 | 27 | public List findAll() { 28 | return employees; 29 | } 30 | 31 | public List findByDepartment(Long departmentId) { 32 | return employees.stream() 33 | .filter(a -> a.getDepartmentId().equals(departmentId)) 34 | .toList(); 35 | } 36 | 37 | public List findByOrganization(Long organizationId) { 38 | return employees.stream() 39 | .filter(a -> a.getOrganizationId().equals(organizationId)) 40 | .toList(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /employee-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: employee-service 4 | 5 | server: 6 | port: 0 7 | 8 | eureka: 9 | client: 10 | serviceUrl: 11 | defaultZone: http://localhost:8061/eureka/ 12 | 13 | logging: 14 | pattern: 15 | console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n" 16 | 17 | springdoc: 18 | packagesToScan: com.py.employee -------------------------------------------------------------------------------- /employee-service/src/test/java/pl/piomin/services/employee/EmployeeRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.py.employee; 2 | 3 | import org.junit.jupiter.api.MethodOrderer; 4 | import org.junit.jupiter.api.Order; 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.jupiter.api.TestMethodOrder; 7 | import org.springframework.util.Assert; 8 | import com.py.employee.model.Employee; 9 | import com.py.employee.repository.EmployeeRepository; 10 | 11 | import java.util.List; 12 | 13 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 14 | public class EmployeeRepositoryTest { 15 | 16 | private static final EmployeeRepository repository = new EmployeeRepository(); 17 | 18 | @Test 19 | @Order(1) 20 | void testAddEmployee() { 21 | Employee employee = new Employee(1L, 1L, "Test Test", 100, "Test"); 22 | employee = repository.add(employee); 23 | Assert.notNull(employee, "Employee is null."); 24 | Assert.isTrue(employee.getId() == 1L, "Employee bad id."); 25 | } 26 | 27 | @Test 28 | @Order(2) 29 | void testFindAll() { 30 | List employees = repository.findAll(); 31 | Assert.isTrue(employees.size() == 1, "Employees size is wrong."); 32 | Assert.isTrue(employees.get(0).getId() == 1L, "Employee bad id."); 33 | } 34 | 35 | @Test 36 | @Order(3) 37 | void testFindByDepartment() { 38 | List employees = repository.findByDepartment(1L); 39 | Assert.isTrue(employees.size() == 1, "Employees size is wrong."); 40 | Assert.isTrue(employees.get(0).getId() == 1L, "Employee bad id."); 41 | } 42 | 43 | @Test 44 | @Order(4) 45 | void testFindByOrganization() { 46 | List employees = repository.findByOrganization(1L); 47 | Assert.isTrue(employees.size() == 1, "Employees size is wrong."); 48 | Assert.isTrue(employees.get(0).getId() == 1L, "Employee bad id."); 49 | } 50 | 51 | @Test 52 | @Order(5) 53 | void testFindById() { 54 | Employee employee = repository.findById(1L); 55 | Assert.notNull(employee, "Employee not found."); 56 | Assert.isTrue(employee.getId() == 1L, "Employee bad id."); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /gateway-service/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.classpath 3 | /.project 4 | /.settings/ 5 | -------------------------------------------------------------------------------- /gateway-service/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 11 | 12 | 13 | 14 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 15 | 16 | com.py.gateway.GatewayApplication 17 | java 18 | 19 | 20 | 21 | debug 22 | 23 | jar 24 | 25 | 26 | process-classes 27 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 28 | 29 | 30 | -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} 31 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 32 | 33 | com.py.gateway.GatewayApplication 34 | java 35 | true 36 | 37 | 38 | 39 | profile 40 | 41 | jar 42 | 43 | 44 | process-classes 45 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 46 | 47 | 48 | 49 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 50 | com.py.gateway.GatewayApplication 51 | java 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /gateway-service/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.springframework.boot 6 | spring-boot-starter-parent 7 | 2.6.1 8 | 9 | 10 | gateway-service 11 | com.py 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 17 16 | 2021.0.0 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-starter-gateway 23 | 24 | 25 | org.springframework.cloud 26 | spring-cloud-starter-netflix-eureka-client 27 | 28 | 29 | org.springframework.cloud 30 | spring-cloud-starter-sleuth 31 | 32 | 33 | org.springdoc 34 | springdoc-openapi-webflux-core 35 | 1.5.13 36 | 37 | 38 | org.springdoc 39 | springdoc-openapi-webflux-ui 40 | 1.5.13 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.cloud 48 | spring-cloud-dependencies 49 | ${spring-cloud.version} 50 | pom 51 | import 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-maven-plugin 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /gateway-service/src/main/java/com/py/gateway/GatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.py.gateway; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springdoc.core.GroupedOpenApi; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 10 | import org.springframework.cloud.gateway.route.RouteDefinition; 11 | import org.springframework.cloud.gateway.route.RouteDefinitionLocator; 12 | import org.springframework.context.annotation.Bean; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | @SpringBootApplication 18 | @EnableDiscoveryClient 19 | public class GatewayApplication { 20 | 21 | private static final Logger LOGGER = LoggerFactory.getLogger(GatewayApplication.class); 22 | 23 | public static void main(String[] args) { 24 | SpringApplication.run(GatewayApplication.class, args); 25 | } 26 | 27 | @Autowired 28 | RouteDefinitionLocator locator; 29 | 30 | @Bean 31 | public List apis() { 32 | List groups = new ArrayList<>(); 33 | List definitions = locator.getRouteDefinitions().collectList().block(); 34 | assert definitions != null; 35 | definitions.stream().filter(routeDefinition -> routeDefinition.getId().matches(".*-service")).forEach(routeDefinition -> { 36 | String name = routeDefinition.getId().replaceAll("-service", ""); 37 | groups.add(GroupedOpenApi.builder().pathsToMatch("/" + name + "/**").group(name).build()); 38 | }); 39 | return groups; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /gateway-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8060 3 | 4 | eureka: 5 | client: 6 | serviceUrl: 7 | defaultZone: http://localhost:8061/eureka/ 8 | 9 | logging: 10 | pattern: 11 | console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n" 12 | 13 | spring: 14 | application: 15 | name: gateway-service 16 | cloud: 17 | gateway: 18 | discovery: 19 | locator: 20 | enabled: true 21 | routes: 22 | - id: employee-service 23 | uri: lb://employee-service 24 | predicates: 25 | - Path=/employee/** 26 | filters: 27 | - RewritePath=/employee/(?.*), /$\{path} 28 | - id: department-service 29 | uri: lb://department-service 30 | predicates: 31 | - Path=/department/** 32 | filters: 33 | - RewritePath=/department/(?.*), /$\{path} 34 | - id: organization-service 35 | uri: lb://organization-service 36 | predicates: 37 | - Path=/organization/** 38 | filters: 39 | - RewritePath=/organization/(?.*), /$\{path} 40 | - id: openapi 41 | uri: http://localhost:${server.port} 42 | predicates: 43 | - Path=/v3/api-docs/** 44 | filters: 45 | - RewritePath=/v3/api-docs/(?.*), /$\{path}/v3/api-docs 46 | 47 | springdoc: 48 | swagger-ui: 49 | urls: 50 | - name: employee 51 | url: /v3/api-docs/employee 52 | - name: department 53 | url: /v3/api-docs/department 54 | - name: organization 55 | url: /v3/api-docs/organization -------------------------------------------------------------------------------- /organization-service/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.classpath 3 | /.project 4 | /.settings/ 5 | -------------------------------------------------------------------------------- /organization-service/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 11 | 12 | 13 | 14 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 15 | 16 | com.py.organization.OrganizationApplication 17 | java 18 | 19 | 20 | 21 | debug 22 | 23 | jar 24 | 25 | 26 | process-classes 27 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 28 | 29 | 30 | -agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address} 31 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 32 | 33 | com.py.organization.OrganizationApplication 34 | java 35 | true 36 | 37 | 38 | 39 | profile 40 | 41 | jar 42 | 43 | 44 | process-classes 45 | org.codehaus.mojo:exec-maven-plugin:3.0.0:exec 46 | 47 | 48 | 49 | ${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs} 50 | com.py.organization.OrganizationApplication 51 | java 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /organization-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | org.springframework.boot 5 | spring-boot-starter-parent 6 | 2.6.1 7 | 8 | 9 | organization-service 10 | com.py 11 | 1.0-SNAPSHOT 12 | 13 | 14 | 17 15 | 2021.0.0 16 | 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-dependencies 23 | ${spring-cloud.version} 24 | pom 25 | import 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-netflix-eureka-client 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-openfeign 38 | 39 | 40 | org.springframework.cloud 41 | spring-cloud-openfeign-core 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-web 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-actuator 50 | 51 | 52 | org.springframework.cloud 53 | spring-cloud-starter-sleuth 54 | 55 | 56 | org.springdoc 57 | springdoc-openapi-webmvc-core 58 | 1.5.13 59 | 60 | 61 | org.springframework.boot 62 | spring-boot-starter-test 63 | test 64 | 65 | 66 | 67 | 68 | 69 | 70 | org.springframework.boot 71 | spring-boot-maven-plugin 72 | 73 | 74 | org.jacoco 75 | jacoco-maven-plugin 76 | 0.8.7 77 | 78 | 79 | 80 | prepare-agent 81 | 82 | 83 | 84 | report 85 | test 86 | 87 | report 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/py/organization/OrganizationApplication.java: -------------------------------------------------------------------------------- 1 | package com.py.organization; 2 | 3 | import io.swagger.v3.oas.annotations.OpenAPIDefinition; 4 | import io.swagger.v3.oas.annotations.info.Info; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.cloud.openfeign.EnableFeignClients; 8 | import org.springframework.context.annotation.Bean; 9 | import com.py.organization.model.Organization; 10 | import com.py.organization.repository.OrganizationRepository; 11 | 12 | @SpringBootApplication 13 | @EnableFeignClients 14 | @OpenAPIDefinition(info = 15 | @Info(title = "Organization API", version = "1.0", description = "Documentation Organization API v1.0") 16 | ) 17 | public class OrganizationApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(OrganizationApplication.class, args); 21 | } 22 | 23 | @Bean 24 | OrganizationRepository repository() { 25 | OrganizationRepository repository = new OrganizationRepository(); 26 | repository.add(new Organization("Microsoft", "Redmond, Washington, USA")); 27 | repository.add(new Organization("Oracle", "Redwood City, California, USA")); 28 | return repository; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /organization-service/src/main/java/com/py/organization/client/DepartmentClient.java: -------------------------------------------------------------------------------- 1 | package com.py.organization.client; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.cloud.openfeign.FeignClient; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | 9 | import com.py.organization.model.Department; 10 | 11 | @FeignClient(name = "department-service") 12 | public interface DepartmentClient { 13 | 14 | @GetMapping("/organization/{organizationId}") 15 | public List findByOrganization(@PathVariable("organizationId") Long organizationId); 16 | 17 | @GetMapping("/organization/{organizationId}/with-employees") 18 | public List findByOrganizationWithEmployees(@PathVariable("organizationId") Long organizationId); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/py/organization/client/EmployeeClient.java: -------------------------------------------------------------------------------- 1 | package com.py.organization.client; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.cloud.openfeign.FeignClient; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | 9 | import com.py.organization.model.Employee; 10 | 11 | @FeignClient(name = "employee-service") 12 | public interface EmployeeClient { 13 | 14 | @GetMapping("/organization/{organizationId}") 15 | List findByOrganization(@PathVariable("organizationId") Long organizationId); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/py/organization/controller/OrganizationController.java: -------------------------------------------------------------------------------- 1 | package com.py.organization.controller; 2 | 3 | import java.util.List; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import com.py.organization.client.DepartmentClient; 15 | import com.py.organization.client.EmployeeClient; 16 | import com.py.organization.model.Organization; 17 | import com.py.organization.repository.OrganizationRepository; 18 | 19 | @RestController 20 | public class OrganizationController { 21 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(OrganizationController.class); 23 | 24 | @Autowired 25 | OrganizationRepository repository; 26 | @Autowired 27 | DepartmentClient departmentClient; 28 | @Autowired 29 | EmployeeClient employeeClient; 30 | 31 | @PostMapping 32 | public Organization add(@RequestBody Organization organization) { 33 | LOGGER.info("Organization add: {}", organization); 34 | return repository.add(organization); 35 | } 36 | 37 | @GetMapping 38 | public List findAll() { 39 | LOGGER.info("Organization find"); 40 | return repository.findAll(); 41 | } 42 | 43 | @GetMapping("/{id}") 44 | public Organization findById(@PathVariable("id") Long id) { 45 | LOGGER.info("Organization find: id={}", id); 46 | return repository.findById(id); 47 | } 48 | 49 | @GetMapping("/{id}/with-departments") 50 | public Organization findByIdWithDepartments(@PathVariable("id") Long id) { 51 | LOGGER.info("Organization find: id={}", id); 52 | Organization organization = repository.findById(id); 53 | organization.setDepartments(departmentClient.findByOrganization(organization.getId())); 54 | return organization; 55 | } 56 | 57 | @GetMapping("/{id}/with-departments-and-employees") 58 | public Organization findByIdWithDepartmentsAndEmployees(@PathVariable("id") Long id) { 59 | LOGGER.info("Organization find: id={}", id); 60 | Organization organization = repository.findById(id); 61 | organization.setDepartments(departmentClient.findByOrganizationWithEmployees(organization.getId())); 62 | return organization; 63 | } 64 | 65 | @GetMapping("/{id}/with-employees") 66 | public Organization findByIdWithEmployees(@PathVariable("id") Long id) { 67 | LOGGER.info("Organization find: id={}", id); 68 | Organization organization = repository.findById(id); 69 | organization.setEmployees(employeeClient.findByOrganization(organization.getId())); 70 | return organization; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/py/organization/model/Department.java: -------------------------------------------------------------------------------- 1 | package com.py.organization.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Department { 7 | 8 | private Long id; 9 | private String name; 10 | private List employees = new ArrayList<>(); 11 | 12 | public Department() { 13 | 14 | } 15 | 16 | public Department(String name) { 17 | super(); 18 | this.name = name; 19 | } 20 | 21 | public Long getId() { 22 | return id; 23 | } 24 | 25 | public void setId(Long id) { 26 | this.id = id; 27 | } 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public void setName(String name) { 34 | this.name = name; 35 | } 36 | 37 | public List getEmployees() { 38 | return employees; 39 | } 40 | 41 | public void setEmployees(List employees) { 42 | this.employees = employees; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "Department [id=" + id + ", name=" + name + "]"; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/py/organization/model/Employee.java: -------------------------------------------------------------------------------- 1 | package com.py.organization.model; 2 | 3 | public class Employee { 4 | 5 | private Long id; 6 | private String name; 7 | private int age; 8 | private String position; 9 | 10 | public Employee() { 11 | 12 | } 13 | 14 | public Employee(String name, int age, String position) { 15 | this.name = name; 16 | this.age = age; 17 | this.position = position; 18 | } 19 | 20 | public Long getId() { 21 | return id; 22 | } 23 | 24 | public void setId(Long id) { 25 | this.id = id; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public void setName(String name) { 33 | this.name = name; 34 | } 35 | 36 | public int getAge() { 37 | return age; 38 | } 39 | 40 | public void setAge(int age) { 41 | this.age = age; 42 | } 43 | 44 | public String getPosition() { 45 | return position; 46 | } 47 | 48 | public void setPosition(String position) { 49 | this.position = position; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return "Employee [id=" + id + ", name=" + name + ", position=" + position + "]"; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/py/organization/model/Organization.java: -------------------------------------------------------------------------------- 1 | package com.py.organization.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Organization { 7 | 8 | private Long id; 9 | private String name; 10 | private String address; 11 | private List departments = new ArrayList<>(); 12 | private List employees = new ArrayList<>(); 13 | 14 | public Organization() { 15 | 16 | } 17 | 18 | public Organization(String name, String address) { 19 | this.name = name; 20 | this.address = address; 21 | } 22 | 23 | public Long getId() { 24 | return id; 25 | } 26 | 27 | public void setId(Long id) { 28 | this.id = id; 29 | } 30 | 31 | public String getName() { 32 | return name; 33 | } 34 | 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | 39 | public String getAddress() { 40 | return address; 41 | } 42 | 43 | public void setAddress(String address) { 44 | this.address = address; 45 | } 46 | 47 | public List getDepartments() { 48 | return departments; 49 | } 50 | 51 | public void setDepartments(List departments) { 52 | this.departments = departments; 53 | } 54 | 55 | public List getEmployees() { 56 | return employees; 57 | } 58 | 59 | public void setEmployees(List employees) { 60 | this.employees = employees; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "Organization [id=" + id + ", name=" + name + ", address=" + address + "]"; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/py/organization/repository/OrganizationRepository.java: -------------------------------------------------------------------------------- 1 | package com.py.organization.repository; 2 | 3 | import com.py.organization.model.Organization; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class OrganizationRepository { 9 | 10 | private List organizations = new ArrayList<>(); 11 | 12 | public Organization add(Organization organization) { 13 | organization.setId((long) (organizations.size()+1)); 14 | organizations.add(organization); 15 | return organization; 16 | } 17 | 18 | public Organization findById(Long id) { 19 | return organizations.stream() 20 | .filter(a -> a.getId().equals(id)) 21 | .findFirst() 22 | .orElseThrow(); 23 | } 24 | 25 | public List findAll() { 26 | return organizations; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /organization-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: organization-service 4 | 5 | server: 6 | port: 0 7 | 8 | eureka: 9 | client: 10 | serviceUrl: 11 | defaultZone: http://localhost:8061/eureka/ 12 | 13 | logging: 14 | pattern: 15 | console: "%d{yyyy-MM-dd HH:mm:ss} ${LOG_LEVEL_PATTERN:-%5p} %m%n" 16 | 17 | springdoc: 18 | packagesToScan: com.py.organization -------------------------------------------------------------------------------- /organization-service/src/test/java/OrganizationRepositoryTest.java: -------------------------------------------------------------------------------- 1 | import org.junit.jupiter.api.MethodOrderer; 2 | import org.junit.jupiter.api.Order; 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.TestMethodOrder; 5 | import org.springframework.util.Assert; 6 | import com.py.organization.model.Organization; 7 | import com.py.organization.repository.OrganizationRepository; 8 | 9 | import java.util.List; 10 | 11 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 12 | public class OrganizationRepositoryTest { 13 | 14 | private static OrganizationRepository repository = new OrganizationRepository(); 15 | 16 | @Test 17 | @Order(1) 18 | public void testAddOrganization() { 19 | Organization organization = new Organization("Test", "Test Street"); 20 | organization = repository.add(organization); 21 | Assert.notNull(organization, "Organization is null."); 22 | Assert.isTrue(organization.getId() == 1L, "Organization bad id."); 23 | } 24 | 25 | @Test 26 | @Order(2) 27 | public void testFindAll() { 28 | List organizations = repository.findAll(); 29 | Assert.isTrue(organizations.size() == 1, "Organizations size is wrong."); 30 | Assert.isTrue(organizations.get(0).getId() == 1L, "Organization bad id."); 31 | } 32 | 33 | @Test 34 | @Order(3) 35 | public void testFindById() { 36 | Organization organization = repository.findById(1L); 37 | Assert.notNull(organization, "Organization not found."); 38 | Assert.isTrue(organization.getId() == 1L, "Organization bad id."); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.py 5 | sample-spring-microservices 6 | 1.0-SNAPSHOT 7 | pom 8 | 9 | 10 | 11 | 12 | 13 | discovery-service 14 | config-service 15 | employee-service 16 | department-service 17 | organization-service 18 | gateway-service 19 | 20 | 21 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Microservices with Spring Cloud Demo Project --------------------------------------------------------------------------------