"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;
}
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++