最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?Boot項(xiàng)目使用WebClient調(diào)用第三方接口的詳細(xì)教程(附實(shí)例代碼)

 更新時(shí)間:2025年09月14日 12:01:11   作者:布朗克168  
WebClient是Spring WebFlux模塊提供的一個(gè)非阻塞的基于響應(yīng)式編程的進(jìn)行Http請(qǐng)求的客戶端工具,從Spring5.0開始提供,這篇文章主要介紹了Spring?Boot項(xiàng)目使用WebClient調(diào)用第三方接口的相關(guān)資料,需要的朋友可以參考下

引言

在Spring Boot項(xiàng)目中,WebClient 是Spring WebFlux模塊提供的非阻塞式HTTP客戶端,用于高效地調(diào)用RESTful API。它支持響應(yīng)式編程,性能優(yōu)于傳統(tǒng)的RestTemplate。本教程將逐步指導(dǎo)您從零開始集成和使用WebClient,包括依賴配置、實(shí)例創(chuàng)建、請(qǐng)求構(gòu)建、響應(yīng)處理和完整代碼示例。確保您使用Spring Boot 2.x或更高版本(推薦Spring Boot 3.x)。

一、簡(jiǎn)單說(shuō)明

步驟1: 添加依賴

首先,在您的Spring Boot項(xiàng)目中添加必要的依賴。WebClient 需要spring-boot-starter-webflux模塊,它包含響應(yīng)式核心庫(kù)。打開pom.xml文件,添加以下依賴:

<dependencies>
    <!-- Spring WebFlux for WebClient -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <!-- 可選:用于JSON處理,如Jackson -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
</dependencies>

如果您使用Gradle,在build.gradle中添加:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'com.fasterxml.jackson.core:jackson-databind'
}

步驟2: 創(chuàng)建WebClient實(shí)例

WebClient 可以通過(guò)Spring Bean方式全局配置,或直接在代碼中創(chuàng)建。推薦使用Bean方式以便重用和統(tǒng)一配置。

  • 方式1: 通過(guò)Bean全局配置(推薦) 在Spring配置類中定義WebClient Bean。例如,創(chuàng)建一個(gè)WebClientConfig類:

    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()
                    .baseUrl("https://api.example.com") // 設(shè)置基礎(chǔ)URL,可選
                    .defaultHeader("Content-Type", "application/json") // 默認(rèn)請(qǐng)求頭
                    .build();
        }
    }
    
  • 方式2: 直接創(chuàng)建實(shí)例 在需要的地方直接構(gòu)建WebClient

    WebClient webClient = WebClient.create("https://api.example.com");
    

步驟3: 構(gòu)建HTTP請(qǐng)求

WebClient 支持GET、POST、PUT、DELETE等方法。使用鏈?zhǔn)秸{(diào)用來(lái)設(shè)置URL、頭信息、查詢參數(shù)和請(qǐng)求體。

  • GET請(qǐng)求示例:調(diào)用一個(gè)第三方API獲取數(shù)據(jù)。

    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.core.publisher.Mono;
    
    public class ApiClient {
        private final WebClient webClient;
    
        public ApiClient(WebClient webClient) {
            this.webClient = webClient;
        }
    
        public Mono<String> getData(String apiPath) {
            return webClient.get()
                    .uri(apiPath) // 例如: "/users"
                    .header("Authorization", "Bearer your_token") // 添加認(rèn)證頭
                    .retrieve() // 發(fā)送請(qǐng)求
                    .bodyToMono(String.class); // 將響應(yīng)體解析為String
        }
    }
    
  • POST請(qǐng)求示例:發(fā)送JSON數(shù)據(jù)到第三方API。

    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.core.publisher.Mono;
    
    public class ApiClient {
        public Mono<String> postData(String apiPath, Object requestBody) {
            return webClient.post()
                    .uri(apiPath)
                    .header("Content-Type", "application/json")
                    .bodyValue(requestBody) // 設(shè)置請(qǐng)求體,自動(dòng)序列化為JSON
                    .retrieve()
                    .bodyToMono(String.class);
        }
    }
    

步驟4: 處理響應(yīng)

WebClient 返回MonoFlux對(duì)象,您需要訂閱來(lái)處理響應(yīng)。響應(yīng)處理包括錯(cuò)誤處理和反序列化。

  • 基本響應(yīng)處理:使用block()同步獲取結(jié)果(不推薦在生產(chǎn)中用,測(cè)試可用),或異步處理。

    // 在Service類中調(diào)用
    public class UserService {
        private final ApiClient apiClient;
    
        public UserService(ApiClient apiClient) {
            this.apiClient = apiClient;
        }
    
        public String fetchUserData() {
            Mono<String> response = apiClient.getData("/users/1");
            return response.block(); // 同步獲取,僅用于演示
        }
    }
    
  • 異步處理(推薦):在Controller中使用響應(yīng)式風(fēng)格。

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Mono;
    
    @RestController
    public class UserController {
        private final ApiClient apiClient;
    
        public UserController(ApiClient apiClient) {
            this.apiClient = apiClient;
        }
    
        @GetMapping("/user")
        public Mono<String> getUser() {
            return apiClient.getData("/users/1")
                    .onErrorResume(e -> Mono.just("Error: " + e.getMessage())); // 錯(cuò)誤處理
        }
    }
    
  • 反序列化為對(duì)象:如果第三方API返回JSON,使用Jackson自動(dòng)映射到Java對(duì)象。

    public class User {
        private Long id;
        private String name;
        // Getters and setters
    }
    
    // 在ApiClient中
    public Mono<User> getUserObject(String apiPath) {
        return webClient.get()
                .uri(apiPath)
                .retrieve()
                .bodyToMono(User.class); // 直接映射到User對(duì)象
    }
    

步驟5: 完整示例代碼

以下是一個(gè)完整的Spring Boot應(yīng)用示例,包括配置、服務(wù)和控制器。

  1. 配置類 (WebClientConfig.java):

    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()
                    .baseUrl("https://jsonplaceholder.typicode.com") // 免費(fèi)測(cè)試API
                    .build();
        }
    }
    
  2. API客戶端 (ApiClient.java):

    import org.springframework.stereotype.Component;
    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.core.publisher.Mono;
    
    @Component
    public class ApiClient {
        private final WebClient webClient;
    
        public ApiClient(WebClient webClient) {
            this.webClient = webClient;
        }
    
        public Mono<String> getPosts() {
            return webClient.get()
                    .uri("/posts")
                    .retrieve()
                    .bodyToMono(String.class);
        }
    }
    
  3. 控制器 (UserController.java):

    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Mono;
    
    @RestController
    public class UserController {
        private final ApiClient apiClient;
    
        public UserController(ApiClient apiClient) {
            this.apiClient = apiClient;
        }
    
        @GetMapping("/posts")
        public Mono<String> getPosts() {
            return apiClient.getPosts();
        }
    }
    
  4. 主應(yīng)用 (SpringBootApplication.java):

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    

常見問(wèn)題和最佳實(shí)踐

  • 錯(cuò)誤處理:使用onErrorResumeonStatus處理HTTP錯(cuò)誤(例如404或500)。

    return webClient.get()
            .uri("/invalid-path")
            .retrieve()
            .onStatus(status -> status.is4xxClientError(), response -> 
                    Mono.error(new RuntimeException("Client error")))
            .bodyToMono(String.class);
    
  • 超時(shí)配置:設(shè)置請(qǐng)求超時(shí),避免阻塞。

    WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(
                    HttpClient.create().responseTimeout(Duration.ofSeconds(10))
            ))
            .build();
    
  • 性能優(yōu)化WebClient是非阻塞的,適合高并發(fā)場(chǎng)景。確保整個(gè)調(diào)用鏈?zhǔn)褂庙憫?yīng)式編程(如返回Mono/Flux)。

  • 測(cè)試:使用WebTestClient進(jìn)行單元測(cè)試,模擬第三方API。

總結(jié)

通過(guò)本教程,您學(xué)會(huì)了在Spring Boot中使用WebClient調(diào)用第三方接口:

  1. 添加spring-boot-starter-webflux依賴。
  2. 配置WebClient Bean。
  3. 構(gòu)建GET/POST請(qǐng)求并處理響應(yīng)。
  4. 使用異步處理和錯(cuò)誤機(jī)制。
  5. 完整代碼示例可直接運(yùn)行。

WebClient 的優(yōu)勢(shì)包括高吞吐量、低資源消耗和現(xiàn)代化API設(shè)計(jì)。如果您遇到問(wèn)題,請(qǐng)參考Spring官方文檔。在實(shí)際項(xiàng)目中,確保添加日志和監(jiān)控以跟蹤請(qǐng)求。

二、抽象化設(shè)計(jì)

以下是根據(jù)需求設(shè)計(jì)的Spring Boot項(xiàng)目結(jié)構(gòu),包含通用API Service封裝、業(yè)務(wù)Service及調(diào)用示例:

一、全局WebClient配置

@Configuration
public class WebClientConfig {

    @Bean
    public WebClient webClient() {
        return WebClient.builder()
                .filter(logRequest()) // 請(qǐng)求日志過(guò)濾器
                .filter(logResponse()) // 響應(yīng)日志過(guò)濾器
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .build();
    }

    private ExchangeFilterFunction logRequest() {
        return (request, next) -> {
            log.info("Request: {} {}", request.method(), request.url());
            request.headers().forEach((name, values) -> 
                values.forEach(value -> log.info("Header: {}={}", name, value)));
            return next.exchange(request);
        };
    }

    private ExchangeFilterFunction logResponse() {
        return ExchangeFilterFunction.ofResponseProcessor(response -> {
            log.info("Response status: {}", response.statusCode());
            return Mono.just(response);
        });
    }
}

二、通用API Service封裝

@Service
@Slf4j
public class ApiService {

    private final WebClient webClient;

    public ApiService(WebClient webClient) {
        this.webClient = webClient;
    }

    // 同步調(diào)用
    public <T, R> R callSync(String url, 
                            HttpMethod method, 
                            @Nullable T requestBody, 
                            Class<R> responseType, 
                            MultiValueMap<String, String> headers) {
        
        log.info("Request body: {}", toJson(requestBody));
        
        try {
            WebClient.RequestBodySpec requestSpec = webClient.method(method)
                    .uri(url)
                    .headers(h -> h.addAll(headers));

            if (requestBody != null) {
                requestSpec.bodyValue(requestBody);
            }

            return requestSpec.retrieve()
                    .onStatus(HttpStatusCode::isError, this::handleError)
                    .bodyToMono(responseType)
                    .doOnNext(res -> log.info("Response body: {}", toJson(res)))
                    .block();
        } catch (WebClientResponseException e) {
            log.error("API call failed: status={}, body={}", e.getStatusCode(), e.getResponseBodyAsString());
            throw new ApiException("API調(diào)用失敗", e);
        } catch (Exception e) {
            log.error("Unexpected error", e);
            throw new ApiException("系統(tǒng)異常", e);
        }
    }

    // 異步調(diào)用
    public <T, R> Mono<R> callAsync(String url, 
                                    HttpMethod method, 
                                    @Nullable T requestBody, 
                                    Class<R> responseType, 
                                    MultiValueMap<String, String> headers) {
        
        log.info("Async request body: {}", toJson(requestBody));
        
        WebClient.RequestBodySpec requestSpec = webClient.method(method)
                .uri(url)
                .headers(h -> h.addAll(headers));

        if (requestBody != null) {
            requestSpec.bodyValue(requestBody);
        }

        return requestSpec.retrieve()
                .onStatus(HttpStatusCode::isError, this::handleError)
                .bodyToMono(responseType)
                .doOnNext(res -> log.info("Async response body: {}", toJson(res)))
                .onErrorResume(WebClientResponseException.class, ex -> {
                    log.error("Async API error: status={}, body={}", 
                            ex.getStatusCode(), ex.getResponseBodyAsString());
                    return Mono.error(new ApiException("異步調(diào)用失敗", ex));
                });
    }

    private Mono<Throwable> handleError(ClientResponse response) {
        return response.bodyToMono(String.class)
                .flatMap(body -> {
                    log.error("Error response: status={}, body={}", response.statusCode(), body);
                    return Mono.error(new WebClientResponseException(
                            response.statusCode().value(),
                            "API Error",
                            response.headers().asHttpHeaders(),
                            body.getBytes(),
                            StandardCharsets.UTF_8
                    ));
                });
    }

    private String toJson(Object obj) {
        try {
            return new ObjectMapper().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.warn("JSON serialization error", e);
            return "{}";
        }
    }
}

// 自定義異常
public class ApiException extends RuntimeException {
    public ApiException(String message, Throwable cause) {
        super(message, cause);
    }
}

三、業(yè)務(wù)Service實(shí)現(xiàn)

@Service
@Slf4j
public class BusinessService {

    private final ApiService apiService;

    // 業(yè)務(wù)請(qǐng)求體封裝
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class BusinessRequest {
        private String orderId;
        private Integer amount;
    }

    // 業(yè)務(wù)響應(yīng)體封裝
    @Data
    public static class BusinessResponse {
        private String transactionId;
        private LocalDateTime processTime;
    }

    public BusinessResponse executeBusinessLogic(String param) {
        // 1. 構(gòu)建請(qǐng)求參數(shù)
        BusinessRequest request = new BusinessRequest(param, 100);
        HttpHeaders headers = new HttpHeaders();
        headers.add("X-Client-ID", "business-service");

        // 2. 調(diào)用API
        return apiService.callSync(
                "https://api.thirdparty.com/endpoint",
                HttpMethod.POST,
                request,
                BusinessResponse.class,
                headers
        );
    }

    public Mono<BusinessResponse> executeAsyncBusiness(String param) {
        BusinessRequest request = new BusinessRequest(param, 200);
        HttpHeaders headers = new HttpHeaders();
        headers.add("X-Async", "true");

        return apiService.callAsync(
                "https://api.thirdparty.com/async",
                HttpMethod.POST,
                request,
                BusinessResponse.class,
                headers
        );
    }
}

四、Controller調(diào)用示例

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class BusinessController {

    private final BusinessService businessService;

    @PostMapping("/process")
    public ResponseEntity<BusinessService.BusinessResponse> processOrder(@RequestParam String orderId) {
        return ResponseEntity.ok(businessService.executeBusinessLogic(orderId));
    }
}

五、定時(shí)任務(wù)調(diào)用示例

@Component
@Slf4j
@RequiredArgsConstructor
public class ScheduledTask {

    private final BusinessService businessService;

    @Scheduled(fixedRate = 30000)
    public void runBatchJob() {
        businessService.executeAsyncBusiness("BATCH_001")
                .subscribe(
                        response -> log.info("Batch processed: {}", response.getTransactionId()),
                        error -> log.error("Batch failed", error)
                );
    }
}

六、關(guān)鍵設(shè)計(jì)說(shuō)明

  1. 日志記錄

    • 使用SLF4J的@Slf4j注解
    • 記錄原始請(qǐng)求/響應(yīng)JSON(通過(guò)Jackson序列化)
    • 異常場(chǎng)景單獨(dú)記錄錯(cuò)誤日志
  2. 異常處理

    • 自定義ApiException統(tǒng)一封裝異常
    • 區(qū)分HTTP錯(cuò)誤狀態(tài)碼(4xx/5xx)
    • 處理網(wǎng)絡(luò)超時(shí)等底層異常
  3. 類型安全

    • 請(qǐng)求/響應(yīng)使用泛型參數(shù)化
    • 業(yè)務(wù)層DTO對(duì)象封裝數(shù)據(jù)
    • 支持任意復(fù)雜對(duì)象自動(dòng)序列化
  4. 全局配置

    • WebClient統(tǒng)一配置超時(shí)/編碼/攔截器
    • 通過(guò)過(guò)濾器實(shí)現(xiàn)全局日志
    • 默認(rèn)JSON內(nèi)容類型
  5. 調(diào)用方式

    • 同步調(diào)用:直接返回結(jié)果對(duì)象
    • 異步調(diào)用:返回Mono<T>響應(yīng)式流
    • 支持GET/POST等HTTP方法

使用示例:業(yè)務(wù)Service只需關(guān)注自身DTO定義,調(diào)用時(shí)傳入U(xiǎn)RL、方法類型、請(qǐng)求對(duì)象和響應(yīng)類型即可完成三方接口調(diào)用,日志和異常處理由底層自動(dòng)完成。

總結(jié) 

到此這篇關(guān)于Spring Boot項(xiàng)目使用WebClient調(diào)用第三方接口的文章就介紹到這了,更多相關(guān)SpringBoot用WebClient調(diào)用第三方接口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • idea.vmoptions 最佳配置方案

    idea.vmoptions 最佳配置方案

    本文介紹了針對(duì)IntelliJ IDEA的優(yōu)化配置建議,包括提升內(nèi)存設(shè)置、啟用G1垃圾回收器、優(yōu)化垃圾回收策略以及調(diào)整網(wǎng)絡(luò)設(shè)置等,旨在提高IDE的性能和響應(yīng)速度,同時(shí),指導(dǎo)用戶如何修改vmoptions文件以應(yīng)用這些配置,并提供了監(jiān)控內(nèi)存使用和插件管理的建議
    2024-09-09
  • 使用Java拼接長(zhǎng)圖/網(wǎng)格圖的避坑指南

    使用Java拼接長(zhǎng)圖/網(wǎng)格圖的避坑指南

    在日常開發(fā)中,我們經(jīng)常會(huì)遇到需要將多張圖片拼接成一張大圖的場(chǎng)景,今天就來(lái)盤點(diǎn)一下 Java 圖片拼接中最容易踩的 4 個(gè)大坑,以及完美的避坑指南,需要的朋友可以參考下
    2026-04-04
  • SpringBoot的pom文件、容器、組件使用及說(shuō)明

    SpringBoot的pom文件、容器、組件使用及說(shuō)明

    本文主要介紹了SpringBoot的配置文件、Spring的生命周期、內(nèi)置容器(Tomcat、Jetty、Undertow、Netty)的性能調(diào)優(yōu)和熱加載/熱部署,以及Spring框架中的重要組件
    2025-11-11
  • 一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法

    一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法

    這篇文章主要介紹了一個(gè)applicationContext 加載錯(cuò)誤導(dǎo)致的阻塞問(wèn)題及解決方法,需要的朋友可以參考下
    2018-11-11
  • SpringSecurity HttpSecurity 類處理流程分析

    SpringSecurity HttpSecurity 類處理流程分析

    SpringSecurity在SSM項(xiàng)目中使用基于配置文件,通過(guò)XML標(biāo)簽定義認(rèn)證信息,HttpSecurity在SpringBoot中通過(guò)代碼配置實(shí)現(xiàn)與XML相同功能,詳細(xì)介紹了HttpSecurity的類結(jié)構(gòu)、處理過(guò)程及其與SecurityBuilder的關(guān)系,感興趣的朋友一起看看吧
    2024-09-09
  • 一文詳解Spring加載properties文件的方式

    一文詳解Spring加載properties文件的方式

    這篇文章將通過(guò)一些示例為大家詳細(xì)介紹Spring加載properties文件的幾種方式,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-06-06
  • 詳解Java8中的lambda表達(dá)式、::符號(hào)和Optional類

    詳解Java8中的lambda表達(dá)式、::符號(hào)和Optional類

    這篇文章主要介紹了Java8中的lambda表達(dá)式、::符號(hào)和Optional類,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • Java8中Stream的一些神操作

    Java8中Stream的一些神操作

    Stream是Java8中處理集合的關(guān)鍵抽象概念,它可以指定你希望對(duì)集合進(jìn)行的操作,可以執(zhí)行非常復(fù)雜的查找、過(guò)濾和映射數(shù)據(jù)等操作,這篇文章主要給大家介紹了Java8中Stream的一些神操作,需要的朋友可以參考下
    2021-11-11
  • Spring Security使用Lambda DSL配置流程詳解

    Spring Security使用Lambda DSL配置流程詳解

    Spring Security 5.2 對(duì) Lambda DSL 語(yǔ)法的增強(qiáng),允許使用lambda配置HttpSecurity、ServerHttpSecurity,重要提醒,之前的配置方法仍然有效。lambda的添加旨在提供更大的靈活性,但是用法是可選的。讓我們看一下HttpSecurity的lambda配置與以前的配置樣式相比
    2023-02-02
  • SpringBoot普通類獲取spring容器中bean的操作

    SpringBoot普通類獲取spring容器中bean的操作

    這篇文章主要介紹了SpringBoot普通類獲取spring容器中bean的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09

最新評(píng)論

铁岭县| 白水县| 三河市| 大名县| 北碚区| 和龙市| 和龙市| 噶尔县| 宜春市| 收藏| 龙胜| 石景山区| 祥云县| 兴义市| 三都| 射阳县| 共和县| 长阳| 连城县| 手游| 辽中县| 乳山市| 绥德县| 湘阴县| 石门县| 遂宁市| 三门峡市| 万宁市| 靖边县| 西华县| 五常市| 阿克陶县| 凌云县| 滦平县| 康定县| 昌图县| 延边| 阳谷县| 阿鲁科尔沁旗| 阜南县| 莱芜市|