WebClient হলো Spring WebFlux-এর অংশ, যা non-blocking I/O এর মাধ্যমে REST API কল করতে ব্যবহৃত হয়। এটি RestTemplate-এর একটি উন্নত বিকল্প এবং Reactive Programming সমর্থন করে। WebClient ব্যবহার করে আপনি সহজেই HTTP কল করতে পারেন, কাস্টমাইজ করতে পারেন, এবং পারফরম্যান্স বাড়াতে পারেন।
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Gradle:
implementation 'org.springframework.boot:spring-boot-starter-webflux'
WebClient ব্যবহার করার জন্য এটি একটি Bean হিসাবে কনফিগার করা যেতে পারে।
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
return builder
.baseUrl("https://jsonplaceholder.typicode.com")
.defaultHeader("Content-Type", "application/json")
.build();
}
}
কনফিগারেশন ব্যাখ্যা:
baseUrl
: প্রতিটি অনুরোধের জন্য সাধারণ URL সেট করা।defaultHeader
: ডিফল্ট HTTP হেডার যোগ করা।import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
@RestController
public class WebClientController {
private final WebClient webClient;
public WebClientController(WebClient webClient) {
this.webClient = webClient;
}
@GetMapping("/get-data")
public String getData() {
return webClient.get()
.uri("/posts/1")
.retrieve()
.bodyToMono(String.class)
.block(); // Synchronous Response
}
}
import java.util.Map;
@PostMapping("/post-data")
public String postData() {
Map<String, String> requestBody = Map.of(
"title", "foo",
"body", "bar",
"userId", "1"
);
return webClient.post()
.uri("/posts")
.bodyValue(requestBody)
.retrieve()
.bodyToMono(String.class)
.block();
}
@PutMapping("/update-data")
public String updateData() {
Map<String, String> requestBody = Map.of(
"id", "1",
"title", "Updated Title",
"body", "Updated Body",
"userId", "1"
);
return webClient.put()
.uri("/posts/1")
.bodyValue(requestBody)
.retrieve()
.bodyToMono(String.class)
.block();
}
@DeleteMapping("/delete-data")
public void deleteData() {
webClient.delete()
.uri("/posts/1")
.retrieve()
.toBodilessEntity()
.block();
}
অনুরোধের সময় ডায়নামিক হেডার যোগ করতে পারেন।
webClient.get()
.uri("/posts/1")
.header("Authorization", "Bearer YOUR_TOKEN")
.retrieve()
.bodyToMono(String.class)
.block();
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import reactor.netty.http.client.HttpClient;
import java.time.Duration;
@Configuration
public class WebClientTimeoutConfig {
@Bean
public WebClient webClientWithTimeout() {
HttpClient httpClient = HttpClient.create()
.responseTimeout(Duration.ofSeconds(5)); // 5 সেকেন্ড টাইমআউট
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
}
webClient.get()
.uri("/posts/1")
.retrieve()
.onStatus(status -> status.is4xxClientError(), response ->
Mono.error(new RuntimeException("Client Error"))
)
.onStatus(status -> status.is5xxServerError(), response ->
Mono.error(new RuntimeException("Server Error"))
)
.bodyToMono(String.class)
.block();
@GetMapping("/async-get-data")
public Mono<String> getDataAsync() {
return webClient.get()
.uri("/posts/1")
.retrieve()
.bodyToMono(String.class);
}
Spring Boot অ্যাপ্লিকেশনে WebClient-এর জন্য লগিং চালু করতে পারেন।
application.properties
:
logging.level.org.springframework.web.reactive.function.client.WebClient=DEBUG
WebClient-এর জন্য মেট্রিকস সক্রিয় করতে Spring Boot Actuator ব্যবহার করতে পারেন।
Dependency:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
WebClient একটি অত্যন্ত শক্তিশালী এবং কাস্টমাইজেবল HTTP ক্লায়েন্ট, যা non-blocking এবং reactive প্রোগ্রামিং এর জন্য আদর্শ। এটি RestTemplate-এর একটি উন্নত বিকল্প, যা Spring Boot-এর আধুনিক অ্যাপ্লিকেশনের জন্য উপযুক্ত।
প্রয়োজনে WebClient নিয়ে আরও বিস্তারিত জানার জন্য প্রশ্ন করতে পারেন। 😊
WebClient
হলো Spring WebFlux-এর অংশ এবং এটি Spring 5 থেকে চালু হয়েছে। এটি একটি নন-ব্লকিং, রিয়্যাকটিভ HTTP ক্লায়েন্ট, যা RestTemplate-এর বিকল্প হিসেবে ব্যবহৃত হয়।
Spring Boot-এ WebClient ব্যবহারের জন্য আপনাকে একটি Bean তৈরি করতে হবে। এটি সাধারণত একটি কনফিগারেশন ক্লাসে তৈরি করা হয়।
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
return builder.build(); // ডিফল্ট কনফিগারেশন সহ WebClient
}
}
Base URL
সহ WebClient Beanimport org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
return builder
.baseUrl("https://api.example.com") // নির্দিষ্ট বেস URL
.build();
}
}
HTTP রিকোয়েস্টের জন্য টাইমআউট কনফিগার করা যেতে পারে।
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import java.time.Duration;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
HttpClient httpClient = HttpClient.create()
.responseTimeout(Duration.ofSeconds(5)); // রেসপন্স টাইমআউট 5 সেকেন্ড
return builder
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
return builder
.defaultHeader("Authorization", "Bearer <your-token>") // ডিফল্ট হেডার
.defaultHeader("Content-Type", "application/json") // কনটেন্ট টাইপ
.build();
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.transport.logging.AdvancedByteBufFormat;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(WebClient.Builder builder) {
HttpClient httpClient = HttpClient.create()
.wiretap("reactor.netty.client.HttpClient",
reactor.netty.LogLevel.DEBUG,
AdvancedByteBufFormat.TEXTUAL);
return builder
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
}
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@Service
public class ApiService {
private final WebClient webClient;
public ApiService(WebClient webClient) {
this.webClient = webClient;
}
public String getExampleData(String endpoint) {
return webClient.get()
.uri(endpoint)
.retrieve()
.bodyToMono(String.class) // JSON রেসপন্সকে String-এ রূপান্তর
.block(); // সিঙ্ক্রোনাস রেসপন্সের জন্য
}
}
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@Service
public class ApiService {
private final WebClient webClient;
public ApiService(WebClient webClient) {
this.webClient = webClient;
}
public String postExampleData(String endpoint, Object payload) {
return webClient.post()
.uri(endpoint)
.bodyValue(payload) // রিকোয়েস্ট বডি
.retrieve()
.bodyToMono(String.class)
.block();
}
}
import org.springframework.web.reactive.function.client.WebClient;
import reactor.util.retry.Retry;
import java.time.Duration;
public class ApiService {
private final WebClient webClient;
public ApiService(WebClient webClient) {
this.webClient = webClient;
}
public String getDataWithTimeout(String endpoint) {
return webClient.get()
.uri(endpoint)
.retrieve()
.bodyToMono(String.class)
.timeout(Duration.ofSeconds(3)) // 3 সেকেন্ড টাইমআউট
.retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(1))) // 3 বার রিট্রাই করবে
.block();
}
}
WebClient
ব্যবহারের পরামর্শ দেওয়া হয়।WebClient
Bean তৈরি করে এবং কনফিগার করে আপনি HTTP API কল করা সহজেই ম্যানেজ করতে পারবেন।
স্প্রিং বুটে RestTemplate
ব্যবহার করে Custom HTTP Headers এবং Query Parameters যোগ করতে নিচের ধাপগুলো অনুসরণ করতে পারেন:
HttpHeaders
এবং HttpEntity
ব্যবহার:আপনি HttpHeaders
ক্লাস ব্যবহার করে কাস্টম হেডার তৈরি করতে পারেন এবং এটি HttpEntity
এর মধ্যে পাস করতে হবে।
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ApiService {
private final RestTemplate restTemplate;
public ApiService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getWithCustomHeaders(String url) {
// Create custom headers
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer some_token");
headers.set("Custom-Header", "CustomValue");
// Wrap headers in HttpEntity
HttpEntity<String> entity = new HttpEntity<>(headers);
// Make GET request with headers
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
return response.getBody();
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Client {
@Autowired
private ApiService apiService;
public void getRequestWithHeaders() {
String url = "http://example.com/api/resource";
String response = apiService.getWithCustomHeaders(url);
System.out.println(response);
}
}
UriComponentsBuilder
ব্যবহার:UriComponentsBuilder
ব্যবহার করে ডাইনামিকভাবে Query Parameters তৈরি এবং URL এ যোগ করতে পারেন।
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
@Service
public class ApiService {
private final RestTemplate restTemplate;
public ApiService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getWithQueryParameters(String baseUrl, String param1, String param2) {
// Build URL with query parameters
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.queryParam("param1", param1)
.queryParam("param2", param2)
.toUriString();
// Make GET request
return restTemplate.getForObject(url, String.class);
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Client {
@Autowired
private ApiService apiService;
public void getRequestWithQueryParams() {
String baseUrl = "http://example.com/api/resource";
String param1 = "value1";
String param2 = "value2";
String response = apiService.getWithQueryParameters(baseUrl, param1, param2);
System.out.println(response);
}
}
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
@Service
public class ApiService {
private final RestTemplate restTemplate;
public ApiService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getWithHeadersAndParams(String baseUrl, String param1, String param2) {
// Create custom headers
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer some_token");
headers.set("Custom-Header", "CustomValue");
// Wrap headers in HttpEntity
HttpEntity<String> entity = new HttpEntity<>(headers);
// Build URL with query parameters
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.queryParam("param1", param1)
.queryParam("param2", param2)
.toUriString();
// Make GET request with headers and query parameters
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
return response.getBody();
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Client {
@Autowired
private ApiService apiService;
public void getRequestWithHeadersAndParams() {
String baseUrl = "http://example.com/api/resource";
String param1 = "value1";
String param2 = "value2";
String response = apiService.getWithHeadersAndParams(baseUrl, param1, param2);
System.out.println(response);
}
}
HttpHeaders
এবং HttpEntity
ব্যবহার করুন।UriComponentsBuilder
ব্যবহার করুন।এই পদ্ধতিগুলো ব্যবহার করে আপনি আপনার স্প্রিং বুট ক্লায়েন্টে কাস্টম হেডার এবং কুয়েরি প্যারামিটার যোগ করতে পারবেন।
Spring Boot WebClient ব্যবহার করে OAuth 2.0 এবং Token Based Authentication ইমপ্লিমেন্ট করা অত্যন্ত গুরুত্বপূর্ণ এবং জনপ্রিয় নিরাপত্তা ব্যবস্থা। এটি ব্যবহারকারীর অনুমোদিত টোকেন (Bearer Token) এর মাধ্যমে API-তে অ্যাক্সেস প্রদান করে। নিচে WebClient এর মাধ্যমে এই ফিচারগুলো ইমপ্লিমেন্ট করার বিস্তারিত দেখানো হয়েছে:
OAuth 2.0 এবং WebClient ব্যবহারের জন্য নিম্নলিখিত ডিপেনডেন্সি যোগ করুন:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
Spring Security এবং OAuth 2.0 এর মাধ্যমে WebClient কনফিগার করতে application.yml
বা application.properties
ফাইল আপডেট করতে হবে।
spring:
security:
oauth2:
client:
registration:
my-client:
client-id: YOUR_CLIENT_ID
client-secret: YOUR_CLIENT_SECRET
scope: read
authorization-grant-type: client_credentials
token-uri: https://auth-server.com/oauth/token
WebClient কনফিগার করার জন্য একটি @Bean
ডিফাইন করতে হবে, যা স্বয়ংক্রিয়ভাবে OAuth 2.0 Token ব্যবহারে সক্ষম হবে।
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProvider;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizedClientManager;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
return WebClient.builder()
.filter(new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager))
.build();
}
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
WebClient Bean ব্যবহার করে OAuth 2.0 টোকেন সহ API কল করা যেতে পারে।
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@Service
public class ApiService {
@Autowired
private WebClient webClient;
public String fetchProtectedData() {
String url = "https://api.example.com/protected-resource";
return webClient
.get()
.uri(url)
.retrieve()
.bodyToMono(String.class)
.block(); // Blocking call for simplicity
}
}
OAuth 2.0 এর বাইরেও সরাসরি Bearer Token দিয়ে API অ্যাক্সেস করা সম্ভব।
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
return WebClient.builder()
.defaultHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN")
.build();
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@Service
public class ApiService {
@Autowired
private WebClient webClient;
public String fetchProtectedData() {
String url = "https://api.example.com/protected-resource";
return webClient
.get()
.uri(url)
.retrieve()
.bodyToMono(String.class)
.block();
}
}
.onStatus()
ব্যবহার করে HTTP স্ট্যাটাস কোড চেক এবং এক্সসেপশন হ্যান্ডল করা যেতে পারে।{
"data": "This is a protected resource response.",
"status": "success"
}
এভাবে, Spring Boot WebClient ব্যবহার করে OAuth 2.0 এবং Token Based Authentication ইমপ্লিমেন্ট করতে পারবেন।
নিচে স্প্রিং বুট ক্লায়েন্টে (Spring Boot Client) WebClient
ব্যবহার করে একটি উদাহরণ দেখানো হয়েছে। WebClient
আধুনিক পদ্ধতি যা স্প্রিং বুট ২.০ থেকে পরিচিত এবং এটি non-blocking এবং reactive প্রোগ্রামিং সমর্থন করে।
Spring Initializr
-এ যান এবং Spring Boot Starter WebFlux
ডিপেনডেন্সি যুক্ত করে একটি নতুন প্রজেক্ট তৈরি করুন।
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
</dependencies>
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;
@Configuration
public class WebClientConfig {
@Bean
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
@Service
public class ApiClient {
private final WebClient webClient;
public ApiClient(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("https://jsonplaceholder.typicode.com").build();
}
// GET রিকোয়েস্ট
public Mono<String> getData(String endpoint) {
return webClient.get()
.uri(endpoint)
.retrieve()
.bodyToMono(String.class);
}
// POST রিকোয়েস্ট
public Mono<String> postData(String endpoint, Object requestBody) {
return webClient.post()
.uri(endpoint)
.bodyValue(requestBody)
.retrieve()
.bodyToMono(String.class);
}
}
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
public class ClientController {
private final ApiClient apiClient;
public ClientController(ApiClient apiClient) {
this.apiClient = apiClient;
}
// GET রিকোয়েস্ট
@GetMapping("/fetch-data")
public Mono<String> fetchData() {
String endpoint = "/posts/1"; // উদাহরণ API Endpoint
return apiClient.getData(endpoint);
}
// POST রিকোয়েস্ট
@PostMapping("/send-data")
public Mono<String> sendData(@RequestBody Object requestBody) {
String endpoint = "/posts"; // উদাহরণ API Endpoint
return apiClient.postData(endpoint, requestBody);
}
}
http://localhost:8080/fetch-data
https://jsonplaceholder.typicode.com/posts/1
থেকে ডেটা রিট্রিভ করবে।http://localhost:8080/send-data
Request Body (JSON):
{
"title": "foo",
"body": "bar",
"userId": 1
}
https://jsonplaceholder.typicode.com/posts
API-তে POST করবে এবং রেসপন্স ফিরিয়ে দেবে।WebClient
এর reactive nature এর কারণে, এটি Mono
বা Flux
টাইপের ডেটা রিটার্ন করে, যা asynchronous ডেটা প্রসেস করতে ব্যবহার করা হয়। এটি ব্লকিং ছাড়াই API থেকে ডেটা রিট্রিভ করতে পারে।
public Mono<String> getData(String endpoint) {
return webClient.get()
.uri(endpoint)
.retrieve()
.onStatus(
status -> status.is4xxClientError() || status.is5xxServerError(),
clientResponse -> Mono.error(new RuntimeException("Error: " + clientResponse.statusCode()))
)
.bodyToMono(String.class)
.onErrorResume(e -> Mono.just("Fallback Response: " + e.getMessage()));
}
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
{
"id": 101,
"title": "foo",
"body": "bar",
"userId": 1
}
Mono
এবং Flux
ডেটা স্ট্রিম ম্যানেজ করতে ব্যবহৃত হয়।
WebClient
হল Spring-এর ভবিষ্যত API ক্লায়েন্ট। তাই নতুন প্রজেক্টেRestTemplate
এর পরিবর্তেWebClient
ব্যবহার করার সুপারিশ করা হয়।
Read more