欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot3-WebClient配置與使用詳解

 更新時間:2024年12月25日 15:15:36   作者:CoderJia  
WebClient是Spring 5引入的響應(yīng)式Web客戶端,用于執(zhí)行HTTP請求,相比傳統(tǒng)的RestTemplate,WebClient提供了非阻塞、響應(yīng)式的方式來處理HTTP請求,是Spring推薦的新一代HTTP客戶端工具,本文將詳細(xì)介紹如何在SpringBoot 3.x中配置和使用WebClient,一起看看吧

1. 簡介

WebClient是Spring 5引入的響應(yīng)式Web客戶端,用于執(zhí)行HTTP請求。相比傳統(tǒng)的RestTemplate,WebClient提供了非阻塞、響應(yīng)式的方式來處理HTTP請求,是Spring推薦的新一代HTTP客戶端工具。本文將詳細(xì)介紹如何在SpringBoot 3.x中配置和使用WebClient。

2. 環(huán)境準(zhǔn)備

2.1 依賴配置

pom.xml中添加必要的依賴:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.10</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

3. WebClient配置

3.1 基礎(chǔ)配置

@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient() {
        return WebClient.builder()
                .baseUrl("https://echo.apifox.com")
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
                .build();
    }
}

3.2 高級配置

package com.coderjia.boot3webflux.config;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.resources.ConnectionProvider;
import java.time.Duration;
/**
 * @author CoderJia
 * @create 2024/12/3 下午 09:42
 * @Description
 **/
@Slf4j
@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient() {
        // 配置HTTP連接池
        ConnectionProvider provider = ConnectionProvider.builder("custom")
                .maxConnections(500)
                .maxIdleTime(Duration.ofSeconds(20))
                .build();
        // 配置HTTP客戶端
        HttpClient httpClient = HttpClient.create(provider)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                .responseTimeout(Duration.ofSeconds(5))
                .doOnConnected(conn ->
                        conn.addHandlerLast(new ReadTimeoutHandler(5))
                                .addHandlerLast(new WriteTimeoutHandler(5)));
        // 構(gòu)建WebClient實例
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .baseUrl("https://echo.apifox.com")
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
                // 添加請求日志記錄功能
                .filter(ExchangeFilterFunction.ofRequestProcessor(
                        clientRequest -> {
                            log.debug("Request: {} {}",
                                    clientRequest.method(),
                                    clientRequest.url());
                            return Mono.just(clientRequest);
                        }
                ))
                // 添加響應(yīng)日志記錄功能
                .filter(ExchangeFilterFunction.ofResponseProcessor(
                        clientResponse -> {
                            log.debug("Response status: {}",
                                    clientResponse.statusCode());
                            return Mono.just(clientResponse);
                        }
                ))
                .build();
    }
}

3.3 retrieve()和exchange()區(qū)別

在使用 WebClient 進(jìn)行 HTTP 請求時,retrieve() 和 exchange() 方法都可以用來處理響應(yīng),但它們有不同的用途和行為。以下是它們的主要區(qū)別:
retrieve()

  • 用途:retrieve() 方法用于簡化響應(yīng)處理,特別是當(dāng)你只需要響應(yīng)體時。
  • 自動錯誤處理:retrieve() 會自動處理 HTTP 錯誤狀態(tài)碼(例如 4xx 和 5xx),并拋出 WebClientResponseException 及其子類。
  • 返回值:通常用于直接獲取響應(yīng)體,例如 bodyToMono(String.class) 或 bodyToFlux(String.class)。
  • 適用場景:適用于大多數(shù)常見的請求處理場景,特別是當(dāng)你不需要手動處理響應(yīng)狀態(tài)碼時。

exchange()

  • 用途:exchange() 方法提供了更底層的控制,允許你手動處理響應(yīng),包括響應(yīng)狀態(tài)碼和響應(yīng)頭。
  • 手動錯誤處理:exchange() 不會自動處理 HTTP 錯誤狀態(tài)碼,你需要手動檢查響應(yīng)狀態(tài)碼并進(jìn)行相應(yīng)的處理。
  • 返回值:返回 ClientResponse 對象,你可以從中提取響應(yīng)狀態(tài)碼、響應(yīng)頭和響應(yīng)體。
  • 適用場景:適用于需要手動處理響應(yīng)狀態(tài)碼或響應(yīng)頭的復(fù)雜場景。

示例對比

retrieve()

public Mono<JSONObject> get(String q1) {
    return webClient.get()
            .uri(uriBuilder -> uriBuilder
                    .path("/get")
                    .queryParam("q1", q1)
                    .build())
            .accept(MediaType.APPLICATION_JSON)
            .retrieve()
            .bodyToMono(JSONObject.class);
}

exchange()

public Mono<JSONObject> get(String q1) {
    return webClient.get()
            .uri(uriBuilder -> uriBuilder
                    .path("/get")
                    .queryParam("q1", q1)
                    .build())
            .accept(MediaType.APPLICATION_JSON)
            .exchangeToMono(response -> {
                if (response.statusCode().is2xxSuccessful()) {
                    return response.bodyToMono(JSONObject.class);
                } else {
                    return Mono.error(new RuntimeException("Request failed with status code: " + response.statusCode()));
                }
            });
}

4. 使用示例

4.1 基本請求操作

package com.coderjia.boot3webflux.service;
import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.Resource;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
/**
 * @author CoderJia
 * @create 2024/12/3 下午 10:22
 * @Description
 **/
@Service
public class ApiService {
    @Resource
    private WebClient webClient;
    // GET請求
    public Mono<JSONObject> get(String q1) {
        return webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/get")
                        .queryParam("q1", q1)
                        .build())
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(JSONObject.class);
    }
    // POST請求
    public Mono<JSONObject> post(JSONObject body) {
        return webClient.post()
                .uri("/post")
                .bodyValue(body)
                .retrieve()
                .bodyToMono(JSONObject.class);
    }
    // PUT請求
    public Mono<JSONObject> put(String q1, JSONObject JSONObject) {
        return webClient.put()
                .uri(uriBuilder -> uriBuilder
                        .path("/put")
                        .queryParam("q1", q1)
                        .build())
                .bodyValue(JSONObject)
                .retrieve()
                .bodyToMono(JSONObject.class);
    }
    // DELETE請求
    public Mono<JSONObject> delete(String q1) {
        return webClient.delete()
                .uri(uriBuilder -> uriBuilder
                        .path("/delete")
                        .queryParam("q1", q1)
                        .build())
                .retrieve()
                .bodyToMono(JSONObject.class);
    }
}

效果展示

get

post

put

delete

4.2 處理復(fù)雜響應(yīng)

@Service
public class ApiService {
    // 獲取列表數(shù)據(jù)
    public Flux<JSONObject> getAllUsers() {
        return webClient.get()
                .uri("/users")
                .retrieve()
                .bodyToFlux(JSONObject.class);
    }
    // 處理錯誤響應(yīng)
    public Mono<JSONObject> getUserWithErrorHandling(Long id) {
        return webClient.get()
                .uri("/users/{id}", id)
                .retrieve()
                .onStatus(HttpStatusCode::is4xxClientError, clientResponse -> Mono.error(new RuntimeException("客戶端錯誤")))
                .onStatus(HttpStatusCode::is5xxServerError, clientResponse -> Mono.error(new RuntimeException("服務(wù)器錯誤")))
                .bodyToMono(JSONObject.class);
    }
    // 使用exchange()方法獲取完整響應(yīng)
    public Mono<ResponseEntity<JSONObject>> getUserWithFullResponse(Long id) {
        return webClient.get()
                .uri("/users/{id}", id)
                .accept(MediaType.APPLICATION_JSON)
                .exchange()
                .flatMap(response -> response.toEntity(JSONObject.class));
    }
}

4.3 高級用法

@Service
public class ApiService {
    // 帶請求頭的請求
    public Mono<JSONObject> getUserWithHeaders(Long id, String token) {
        return webClient.get()
                .uri("/users/{id}", id)
                .header("Authorization", "Bearer " + token)
                .retrieve()
                .bodyToMono(JSONObject.class);
    }
    // 帶查詢參數(shù)的請求
    public Flux<JSONObject> searchUsers(String name, int age) {
        return webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("/users/search")
                        .queryParam("name", name)
                        .queryParam("age", age)
                        .build())
                .retrieve()
                .bodyToFlux(JSONObject.class);
    }
    // 文件上傳
    public Mono<String> uploadFile(FilePart filePart) {
        return webClient.post()
                .uri("/upload")
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .body(BodyInserters.fromMultipartData("file", filePart))
                .retrieve()
                .bodyToMono(String.class);
    }
}

5. 最佳實踐

合理使用響應(yīng)式類型

  • 使用 Mono 用于單個對象
  • 使用 Flux 用于集合數(shù)據(jù)
  • 注意背壓處理

錯誤處理

 public Mono<JSONObject> getUserWithRetry(Long id) {
     return webClient.get()
             .uri("/users/{id}", id)
             .retrieve()
             .bodyToMono(JSONObject.class)
             .retryWhen(Retry.backoff(3, Duration.ofSeconds(1)))
             .timeout(Duration.ofSeconds(5))
             .onErrorResume(TimeoutException.class,
                     e -> Mono.error(new RuntimeException("請求超時")));
 }

資源管理

  • 使用連接池
  • 設(shè)置適當(dāng)?shù)某瑫r時間
  • 實現(xiàn)優(yōu)雅關(guān)閉

6. 注意事項

  • WebClient 是非阻塞的,需要注意響應(yīng)式編程的特性
  • 合理配置連接池和超時參數(shù)
  • 在生產(chǎn)環(huán)境中實現(xiàn)適當(dāng)?shù)腻e誤處理和重試機制
  • 注意內(nèi)存使用,特別是處理大量數(shù)據(jù)時

7. 與RestTemplate對比

特性WebClientRestTemplate
編程模型響應(yīng)式、非阻塞同步、阻塞
性能更好一般
資源利用更高效一般
學(xué)習(xí)曲線較陡平緩
適用場景高并發(fā)、響應(yīng)式系統(tǒng)簡單應(yīng)用、傳統(tǒng)系統(tǒng)

8. 總結(jié)

WebClient 作為 Spring 推薦的新一代 HTTP 客戶端,提供了強大的響應(yīng)式編程能力和更好的性能。雖然相比 RestTemplate 有一定的學(xué)習(xí)曲線,但在現(xiàn)代微服務(wù)架構(gòu)中,其帶來的好處遠(yuǎn)超過學(xué)習(xí)成本。建議在新項目中優(yōu)先考慮使用WebClient,特別是在需要處理高并發(fā)請求的場景下。

參考資料

到此這篇關(guān)于SpringBoot3-WebClient配置與使用詳解的文章就介紹到這了,更多相關(guān)SpringBoot3 WebClient使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解析Java繼承中方法的覆蓋和重載

    解析Java繼承中方法的覆蓋和重載

    這篇文章主要介紹了Java繼承中方法的覆蓋和重載的詳細(xì)概念及用法,非常的實用,這里推薦給大家,有需要的小伙伴可以參考下。
    2015-05-05
  • Spring boot使用多線程過程步驟解析

    Spring boot使用多線程過程步驟解析

    這篇文章主要介紹了Spring boot使用多線程過程步驟解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • 詳解Spring Boot最核心的27個注解,你了解多少?

    詳解Spring Boot最核心的27個注解,你了解多少?

    這篇文章主要介紹了詳解Spring Boot最核心的27個注解,你了解多少?文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Spring Boot @Async 異步任務(wù)執(zhí)行方法

    Spring Boot @Async 異步任務(wù)執(zhí)行方法

    本篇文章主要介紹了Spring Boot @Async 異步任務(wù)執(zhí)行方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • Java自動生成趨勢比對數(shù)據(jù)的方法分享

    Java自動生成趨勢比對數(shù)據(jù)的方法分享

    這篇文章主要和大家分享了一種Java自動生成趨勢比對數(shù)據(jù)的方法設(shè)計及實現(xiàn),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-04-04
  • SSH框架網(wǎng)上商城項目第22戰(zhàn)之銀行圖標(biāo)以及支付頁面顯示

    SSH框架網(wǎng)上商城項目第22戰(zhàn)之銀行圖標(biāo)以及支付頁面顯示

    這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項目第22戰(zhàn)之銀行圖標(biāo)以及支付頁面顯示,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Spring運行時動態(tài)注冊bean的方法

    Spring運行時動態(tài)注冊bean的方法

    這篇文章主要介紹了Spring運行時動態(tài)注冊bean的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • Java實現(xiàn)Excel文件加密解密的示例代碼

    Java實現(xiàn)Excel文件加密解密的示例代碼

    設(shè)置excel文件保護(hù)時,通??蛇x擇對整個工作簿進(jìn)行加密保護(hù)。無需設(shè)置文檔保護(hù)時,可撤銷密碼保護(hù),即解密文檔。本文將通過java程序演示以上加密、解密方法的實現(xiàn),感興趣的可以了解一下
    2022-05-05
  • 實例詳解MyBatis-plus自動填充功能

    實例詳解MyBatis-plus自動填充功能

    每次對數(shù)據(jù)進(jìn)行新增、刪除、修改時都需要對這些字段進(jìn)行設(shè)置,雖然新增時間和修改時間可以使用數(shù)據(jù)庫的時間,但是新增人和修改人就不能使用這樣的功能,下面小編給大家介紹下MyBatis-plus自動填充功能的實例代碼,感興趣的朋友一起看看吧
    2022-01-01
  • 關(guān)于Java Interface接口的簡單練習(xí)題

    關(guān)于Java Interface接口的簡單練習(xí)題

    這篇文章主要給大家分享的是關(guān)于Java Interface接口的簡單練習(xí)題,難度不算大,但是要有一個清晰的邏輯建立接口和鏈接Java類。下面來看看文章的詳細(xì)介紹吧,需要的朋友可以參考一下
    2021-11-11

最新評論