"Welcome To Ashok IT" "Spring Boot and MicroServices" Topic : MicroServices Communication Date : 27/06/2025 (Session - 75) _____________________________________________________________________________________________________________________________ Last Session ============ * We have seen how to communicate from one microservice(Customer) to another microservice(Address) using RestTemplate technique. * We established the connectivity in the below endpoint of customer microservice Customer -> http://localhost:9966/api/customers/{customerId} ApiResponse -> CustomerDetails -> Customer Information -> AddressDetails -> Address Information of Customer Today Session - WebClient Communication from One Microservice to another Microservice ===================================================================================== * We need to add new starter i.e.,Reactive web starter pom.xml ======= 4.0.0 org.springframework.boot spring-boot-starter-parent 3.5.3 com.ashokit 38_Microservices_Customer 0.0.1-SNAPSHOT 38_Microservices_Customer Demo project for Spring Boot 17 org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-web com.oracle.database.jdbc ojdbc11 runtime org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.modelmapper modelmapper 3.1.1 com.fasterxml.jackson.dataformat jackson-dataformat-xml org.springframework.boot spring-boot-starter-webflux io.projectreactor reactor-test test org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok application.properties ====================== #server port changing server.port=9977 #Database Configuration spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe spring.datasource.username=system spring.datasource.password=manager #Hibernate Configuration spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true #Application name configuration spring.application.name=Customer-Service Customer.java ============= package com.ashokit.entity; import java.time.LocalDateTime; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Entity @Table(name="shopping_customers") @Data @AllArgsConstructor @NoArgsConstructor public class Customer { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="customer_id") private Integer id; @Column(name="name") private String name; @Column(name="location") private String location; @Column(name="gender") private String gender; @Column(name="email_id") private String emailId; @Column(name="contact_no") private String contactNo; @Column(name="created_dt",updatable = false) @CreationTimestamp private LocalDateTime createdDate; @Column(name="updated_dt",insertable = false) @UpdateTimestamp private LocalDateTime updatedDate; } CustomerRequest.java ===================== package com.ashokit.request; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor @Builder public class CustomerRequest { private String name; private String location; private String gender; private String emailId; private String contactNo; } CustomerResponse.java ===================== package com.ashokit.response; import java.time.LocalDateTime; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonInclude(value = Include.NON_NULL) public class CustomerResponse { private Integer id; private String name; private String location; private String gender; private String emailId; private String contactNo; private LocalDateTime createdDate; private LocalDateTime updatedDate; } ApplicationConfig.java ====================== * We need to define WebClient class as spring bean package com.ashokit.config; import org.modelmapper.ModelMapper; import org.modelmapper.convention.MatchingStrategies; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.function.client.WebClient; @Configuration public class ApplicationConfig { @Bean ModelMapper getModelMapper() { ModelMapper mapper = new ModelMapper(); mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); return mapper; } @Bean RestTemplate getRestTemplateObject() { return new RestTemplate(); } @Bean WebClient webClient(WebClient.Builder builder) { return builder.build(); } } CustomerService.java ==================== package com.ashokit.services; import java.util.List; import com.ashokit.request.CustomerRequest; import com.ashokit.response.ApiResponse; import com.ashokit.response.CustomerResponse; public interface CustomerService { public CustomerResponse createCustomer(CustomerRequest customerRequest); public CustomerResponse getCustomerById(Integer customerId); public List getAllCustomers(); } CustomerServiceImpl.java ======================== package com.ashokit.services; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.function.client.WebClient; import com.ashokit.dao.CustomerDao; import com.ashokit.entity.Customer; import com.ashokit.request.CustomerRequest; import com.ashokit.response.AddressResponse; import com.ashokit.response.AddressResponseList; import com.ashokit.response.ApiResponse; import com.ashokit.response.CustomerResponse; @Service public class CustomerServiceImpl implements CustomerService { @Autowired private CustomerDao customerDao; @Autowired private ModelMapper modelMapper; @Autowired private RestTemplate restTemplate; @Autowired private WebClient webClient; @Value("${address.service.name.url}") private String addressServiceUrl; @Override public CustomerResponse createCustomer(CustomerRequest customerRequest) { //converting from CustomerRequest To Entity Class Object Customer customer = convertingFromRequestToEntity(customerRequest); //Saving Customer Information Customer savedCustomer = this.customerDao.save(customer); //Converting From Customer Entity to CustomerResponse Object return this.convertingEntityToResponse(savedCustomer); } @Override public ApiResponse getCustomerById(Integer customerId) { Optional customerDetails = this.customerDao.findById(customerId); if (customerDetails.isPresent()) { Customer custDetails = customerDetails.get(); CustomerResponse customerResponse = this.convertingEntityToResponse(custDetails); //Address Microservice interaction //AddressResponse addressResponse = callingAddressServiceWithRestTemplate(customerId); AddressResponse addressResponse = callingAddressServiceWithWebClient(customerId); //setting addressResponse into customerResponse //customerResponse.setAddressResponse(addressResponse); ApiResponse apiResponse = new ApiResponse(); apiResponse.setCustomerDetails(customerResponse); apiResponse.setAddressDetails(addressResponse); return apiResponse; }else { //throw the exception return null; } } @Override public List getAllCustomers() { //Getting All Customers Details List allCustomers = this.customerDao.findAll(); //converting from List into List Using Java8 streams List allCustomerResponse = allCustomers.stream() // converting the list of customer into stream of customer .map(eachCustomer -> { return convertingEntityToResponse(eachCustomer); }) //It will transform the customer object into customeresponse object .collect(Collectors.toList()); //collecting each customerresponse object into list object //Calling the Address MicroService to get All Addresses AddressResponseList allAddressResponse = callingAddressServiceForAllAddressWithRestTemplate(); System.out.println("All Address Response:::" + allAddressResponse.getAddressResponseList().size()); //Mapping the Address with Customer List customerAddressResponse = new ArrayList<>(); for(CustomerResponse customerResponse: allCustomerResponse) { for(AddressResponse addressResponse1 : allAddressResponse.getAddressResponseList()) { if(customerResponse.getId() == addressResponse1.getCustomerId()) { System.out.println("Inside the condition"); customerResponse.setAddressResponse(addressResponse1); customerAddressResponse.add(customerResponse); } } } return customerAddressResponse; } //utility method for converting customerRequest to Entity Object private Customer convertingFromRequestToEntity(CustomerRequest customerRequest) { Customer customer = modelMapper.map(customerRequest,Customer.class); System.out.println("Customer::::" + customer); return this.modelMapper.map(customerRequest,Customer.class); } //utility method for converting customerRequest to Entity Object private CustomerResponse convertingEntityToResponse(Customer customer) { CustomerResponse custResponse = this.modelMapper.map(customer,CustomerResponse.class); System.out.println("CustomerResponse::::" + custResponse.getCreatedDate()); return custResponse; } //calling the Address microservice to Fetch Address of particular Customer private AddressResponse callingAddressServiceWithRestTemplate(int customerId) { //http://localhost:9966/api/address/ System.out.println("Address Service URL:::" + addressServiceUrl); /*ResponseEntity addressResponseEntity = restTemplate.getForEntity(addressServiceUrl+"customer/{customerId}", AddressResponse.class, customerId );*/ //By Using exchange() of RestTemplate ResponseEntity addressResponseEntity = restTemplate.exchange(addressServiceUrl+"customer/{customerId}", HttpMethod.GET, null, AddressResponse.class, customerId); //checking the API Status if(addressResponseEntity.getStatusCode() == HttpStatus.OK) { //ResponseBody of API if(addressResponseEntity.hasBody()) { return addressResponseEntity.getBody(); } } return null; } private AddressResponse callingAddressServiceWithWebClient(int customerId) { AddressResponse addressResponse = webClient .get() .uri(addressServiceUrl+"customer/"+customerId) .retrieve() .bodyToMono(AddressResponse.class) .block(); return addressResponse; } //calling the Address micro service to Fetch all address private AddressResponseList callingAddressServiceForAllAddressWithRestTemplate() { ResponseEntity addressResponseEntity = restTemplate.exchange(addressServiceUrl, HttpMethod.GET, null, AddressResponseList.class); //checking the API Status if(addressResponseEntity.getStatusCode() == HttpStatus.OK) { //ResponseBody of API if(addressResponseEntity.hasBody()) { return addressResponseEntity.getBody(); } } return null; } } CustomerController.java ======================= package com.ashokit.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ashokit.request.CustomerRequest; import com.ashokit.response.CustomerResponse; import com.ashokit.services.CustomerService; @RestController @RequestMapping(value = "/api/customers") public class CustomerController { @Autowired private CustomerService customerService; @GetMapping(value = "/") public ResponseEntity fetchAllCustomers(){ List allCustomers = customerService.getAllCustomers(); return ResponseEntity.ok(allCustomers); } @GetMapping(value = "/{customerId}") public ResponseEntity fetchCustomerDetailsById(@PathVariable("customerId") Integer customerId){ //FirstTechnique -> Not Readable CustomerResponse customerDetails = customerService.getCustomerById(customerId); return ResponseEntity.ok(customerDetails); } @PostMapping(value = "/") public ResponseEntity createNewCustomer(@RequestBody CustomerRequest customerRequest){ CustomerResponse newCustomerDetails = customerService.createCustomer(customerRequest); return new ResponseEntity<>(newCustomerDetails, HttpStatus.CREATED); } } Customer microservice API's =========================== curl --location 'http://localhost:9977/api/customers/' \ --header 'Content-Type: application/json' \ --data-raw '{ "name" :"Dinesh", "location":"Hyderabad", "gender":"Male", "emailId":"dinesh.ashokit@gmail.com", "contactNo":"12345" }' curl --location 'http://localhost:9977/api/customers/1002' curl --location 'http://localhost:9977/api/customers/' * After completing the developing the Customer-Service & Address-Service * Now We have requirement to pull the Customer Information along with associated Address Information. * We required to communicate from One Microservice to another Microservice using RestTemplate,WebClient,FeignClient * Following are the below endpoints required code changes for Customer-Service endpoints 1) Get Customer By ID --> we are getting customer information based on ID 2) Get All Customers --> We are getting all Customer information Customer-Address MicroService Communication =========================================== ApplicationConfig.java ====================== package com.ashokit.config; import org.modelmapper.ModelMapper; import org.modelmapper.convention.MatchingStrategies; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class ApplicationConfig { @Bean ModelMapper getModelMapper() { ModelMapper mapper = new ModelMapper(); mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); return mapper; } @Bean RestTemplate getRestTemplateObject() { return new RestTemplate(); } } Adding AddressResponse class into response package =================================================== package com.ashokit.response; import java.time.LocalDateTime; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor @JsonInclude(value = Include.NON_NULL) public class AddressResponse { private Integer id; private String doorNo; private String cityName; private String pincode; private LocalDateTime created_dt; private LocalDateTime updated_dt; private Integer customerId; } application.properties ====================== #server port changing server.port=9977 #Database Configuration spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe spring.datasource.username=system spring.datasource.password=manager #Hibernate Configuration spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true #Application name configuration spring.application.name=Customer-Service #Address Microservices Configuration address.service.name.url=http://localhost:9966/api/address/ CustomerResponse.java ===================== package com.ashokit.response; import java.time.LocalDateTime; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonInclude(value = Include.NON_NULL) public class CustomerResponse { private Integer id; private String name; private String location; private String gender; private String emailId; private String contactNo; private LocalDateTime createdDate; private LocalDateTime updatedDate; //Adding AddressResponse in customerResponse private AddressResponse addressResponse; } CustomerService.java ==================== package com.ashokit.services; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import com.ashokit.dao.CustomerDao; import com.ashokit.entity.Customer; import com.ashokit.request.CustomerRequest; import com.ashokit.response.AddressResponse; import com.ashokit.response.ApiResponse; import com.ashokit.response.CustomerResponse; @Service public class CustomerServiceImpl implements CustomerService { @Autowired private CustomerDao customerDao; @Autowired private ModelMapper modelMapper; @Autowired private RestTemplate restTemplate; @Value("${address.service.name.url}") private String addressServiceUrl; @Override public CustomerResponse createCustomer(CustomerRequest customerRequest) { //converting from CustomerRequest To Entity Class Object Customer customer = convertingFromRequestToEntity(customerRequest); //Saving Customer Information Customer savedCustomer = this.customerDao.save(customer); //Converting From Customer Entity to CustomerResponse Object return this.convertingEntityToResponse(savedCustomer); } @Override public ApiResponse getCustomerById(Integer customerId) { Optional customerDetails = this.customerDao.findById(customerId); if (customerDetails.isPresent()) { Customer custDetails = customerDetails.get(); CustomerResponse customerResponse = this.convertingEntityToResponse(custDetails); //Address Microservice interaction AddressResponse addressResponse = callingAddressServiceWithRestTemplate(customerId); //setting addressResponse into customerResponse //customerResponse.setAddressResponse(addressResponse); ApiResponse apiResponse = new ApiResponse(); apiResponse.setCustomerDetails(customerResponse); apiResponse.setAddressDetails(addressResponse); return apiResponse; }else { //throw the exception return null; } } @Override public List getAllCustomers() { //Getting All Customers Details List allCustomers = this.customerDao.findAll(); //converting from List into List Using Java8 streams List allCustomerResponse = allCustomers.stream() // converting the list of customer into stream of customer .map(eachCustomer -> { return convertingEntityToResponse(eachCustomer); }) //It will transform the customer object into customeresponse object .collect(Collectors.toList()); //collecting each customerresponse object into list object return allCustomerResponse; } //utility method for converting customerRequest to Entity Object private Customer convertingFromRequestToEntity(CustomerRequest customerRequest) { Customer customer = modelMapper.map(customerRequest,Customer.class); System.out.println("Customer::::" + customer); return this.modelMapper.map(customerRequest,Customer.class); } //utility method for converting customerRequest to Entity Object private CustomerResponse convertingEntityToResponse(Customer customer) { CustomerResponse custResponse = this.modelMapper.map(customer,CustomerResponse.class); System.out.println("CustomerResponse::::" + custResponse.getCreatedDate()); return custResponse; } //calling the Address microservice to Fetch Address of particular Customer private AddressResponse callingAddressServiceWithRestTemplate(int customerId) { //http://localhost:9966/api/address/ System.out.println("Address Service URL:::" + addressServiceUrl); ResponseEntity addressResponseEntity = restTemplate.getForEntity(addressServiceUrl+"customer/{customerId}", AddressResponse.class, customerId ); //By Using exchange() of RestTemplate /*ResponseEntity addressResponseEntity = restTemplate.exchange(addressServiceUrl+"customer/{customerId}", HttpMethod.GET, null, AddressResponse.class, customerId);*/ //checking the API Status if(addressResponseEntity.getStatusCode() == HttpStatus.OK) { //ResponseBody of API if(addressResponseEntity.hasBody()) { return addressResponseEntity.getBody(); } } return null; } } +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++