|
@@ -0,0 +1,178 @@
|
|
|
+package com.backendsys.modules.common.utils;
|
|
|
+
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.core.io.buffer.DataBuffer;
|
|
|
+import org.springframework.core.io.buffer.DataBufferUtils;
|
|
|
+import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
|
+import org.springframework.http.MediaType;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.util.MultiValueMap;
|
|
|
+import org.springframework.web.reactive.function.client.ClientResponse;
|
|
|
+import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
|
|
+import org.springframework.web.reactive.function.client.ExchangeStrategies;
|
|
|
+import org.springframework.web.reactive.function.client.WebClient;
|
|
|
+import org.springframework.web.util.UriComponentsBuilder;
|
|
|
+import reactor.core.publisher.Flux;
|
|
|
+import reactor.core.publisher.Mono;
|
|
|
+
|
|
|
+import java.nio.ByteBuffer;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
+import java.util.function.Consumer;
|
|
|
+import java.util.function.Function;
|
|
|
+
|
|
|
+
|
|
|
+public class WebClientUtil {
|
|
|
+
|
|
|
+ // 请求/响应拦截器
|
|
|
+ static ExchangeFilterFunction logFilter = (request, next) -> {
|
|
|
+ System.out.println("[logRequestFilter] Request: " + request.method() + " " + request.url());
|
|
|
+ return next.exchange(request).flatMap(response -> {
|
|
|
+
|
|
|
+// System.out.println("[logRequestFilter] Response status code: " + response.statusCode());
|
|
|
+// // 记录响应体内容,但不直接订阅
|
|
|
+// return response.bodyToMono(String.class)
|
|
|
+// .doOnNext(body -> System.out.println("[logRequestFilter] Response body: " + body))
|
|
|
+// .thenReturn(response);
|
|
|
+
|
|
|
+ // 读取并缓存整个响应体
|
|
|
+ return DataBufferUtils.join(response.bodyToFlux(DataBuffer.class))
|
|
|
+ .flatMap(dataBuffer -> {
|
|
|
+ // 提取字节数组并释放缓冲区
|
|
|
+ byte[] bodyBytes = new byte[dataBuffer.readableByteCount()];
|
|
|
+ dataBuffer.read(bodyBytes);
|
|
|
+ DataBufferUtils.release(dataBuffer);
|
|
|
+
|
|
|
+ // 记录响应体
|
|
|
+ String bodyStr = new String(bodyBytes, StandardCharsets.UTF_8);
|
|
|
+ System.out.println("[logRequestFilter] Response body: " + bodyStr);
|
|
|
+
|
|
|
+ // 重新构建完整的响应
|
|
|
+ return Mono.just(ClientResponse.create(response.statusCode())
|
|
|
+ .headers(headers -> headers.addAll(response.headers().asHttpHeaders()))
|
|
|
+ .body(Flux.just(DefaultDataBufferFactory.sharedInstance.wrap(bodyBytes)))
|
|
|
+ .build());
|
|
|
+ });
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ // 实例化 WebClient
|
|
|
+// private static final WebClient webClient = WebClient.builder().build();
|
|
|
+ private static final WebClient webClient = WebClient.builder()
|
|
|
+ .exchangeStrategies(ExchangeStrategies.builder()
|
|
|
+ .codecs(configurer -> configurer.defaultCodecs().enableLoggingRequestDetails(true))
|
|
|
+ .build())
|
|
|
+ .filter(logFilter) // 确保 logFilter 在缓冲后使用
|
|
|
+ .build();
|
|
|
+
|
|
|
+ // 默认的响应类型
|
|
|
+ private static final Class<Object> DEFAULT_RESPONSE_TYPE = Object.class;
|
|
|
+
|
|
|
+ // [Get] 公共逻辑 (参数示例)
|
|
|
+ // - 自定义头部: Consumer<HttpHeaders> httpHeaders = (headers) -> { headers.add("Authorization", "Bearer " + getToken()); };
|
|
|
+ // - 自定义返回类型: Class<T> responseType = JSONObject.class;
|
|
|
+ private static <T> Mono<T> doGetInternal(String url, MultiValueMap<String, String> params, Consumer<HttpHeaders> httpHeaders, Class<T> responseType) {
|
|
|
+ String uri = UriComponentsBuilder.fromUriString(url).queryParams(params).toUriString();
|
|
|
+ return webClient.get().uri(uri).headers(httpHeaders).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(responseType);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同步调用示例:
|
|
|
+ * Mono<JSONObject> responseMono = WebClientUtil.doGet(url);
|
|
|
+ * Mono<JSONObject> responseMono = WebClientUtil.doGet(url, JSONObject.class);
|
|
|
+ * Mono<JSONObject> responseMono = WebClientUtil.doGet(url, params, JSONObject.class);
|
|
|
+ * Mono<JSONObject> responseMono = WebClientUtil.doGet(config.URL + "/v1/images/generations", params, kLingUtil.getHttpHeaders(), JSONObject.class);
|
|
|
+ * return JSONUtil.parseObj(responseMono.block());
|
|
|
+ */
|
|
|
+ // 无参数、无自定义头、无响应类型
|
|
|
+ public static Mono<Object> doGet(String url) {
|
|
|
+ return doGetInternal(url, null, null, DEFAULT_RESPONSE_TYPE);
|
|
|
+ }
|
|
|
+ // 无参数、无自定义头
|
|
|
+ public static <T> Mono<T> doGet(String url, Class<T> responseType) {
|
|
|
+ return doGetInternal(url, null, null, responseType);
|
|
|
+ }
|
|
|
+ // 无参数、有自定义头、无响应类型
|
|
|
+ public static Mono<Object> doGet(String url, Consumer<HttpHeaders> httpHeaders) {
|
|
|
+ return doGetInternal(url, null, httpHeaders, DEFAULT_RESPONSE_TYPE);
|
|
|
+ }
|
|
|
+ // 无参数、有自定义头、有响应类型
|
|
|
+ public static <T> Mono<T> doGet(String url, Consumer<HttpHeaders> httpHeaders, Class<T> responseType) {
|
|
|
+ return doGetInternal(url, null, httpHeaders, responseType);
|
|
|
+ }
|
|
|
+ // 有参数、无自定义头、无响应类型
|
|
|
+ public static Mono<Object> doGet(String url, MultiValueMap<String, String> params) {
|
|
|
+ return doGetInternal(url, params, headers -> {}, DEFAULT_RESPONSE_TYPE);
|
|
|
+ }
|
|
|
+ // 有参数、无自定义头、有响应类型
|
|
|
+ public static <T> Mono<T> doGet(String url, MultiValueMap<String, String> params, Class<T> responseType) {
|
|
|
+ return doGetInternal(url, params, headers -> {}, responseType);
|
|
|
+ }
|
|
|
+ // 有参数、有自定义头、无响应类型
|
|
|
+ public static Mono<Object> doGet(String url, MultiValueMap<String, String> params, Consumer<HttpHeaders> httpHeaders) {
|
|
|
+ return doGetInternal(url, params, httpHeaders, DEFAULT_RESPONSE_TYPE);
|
|
|
+ }
|
|
|
+ // 有参数、有自定义头、有响应类型
|
|
|
+ public static <T> Mono<T> doGet(String url, MultiValueMap<String, String> params, Consumer<HttpHeaders> httpHeaders, Class<T> responseType) {
|
|
|
+ return doGetInternal(url, params, httpHeaders, responseType);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 异步调用示例:
|
|
|
+ * Mono<JSONObject> responseMono = WebClientUtil.doGet(url, JSONObject.class);
|
|
|
+ * Mono<JSONObject> responseMono = WebClientUtil.doGet(url, params, JSONObject.class);
|
|
|
+ * responseMono.subscribe(
|
|
|
+ * response -> System.out.println("Response: " + response),
|
|
|
+ * e -> e.printStackTrace()
|
|
|
+ * );
|
|
|
+ */
|
|
|
+ public static <T> CompletableFuture<T> doGetAsync(String url, Class<T> responseType) {
|
|
|
+ return webClient.get()
|
|
|
+ .uri(url)
|
|
|
+ .accept(MediaType.APPLICATION_JSON)
|
|
|
+ .retrieve()
|
|
|
+ .bodyToMono(responseType)
|
|
|
+ .toFuture();
|
|
|
+ }
|
|
|
+ public static <T> CompletableFuture<T> doGetAsync(String url, MultiValueMap<String, String> params, Class<T> responseType) {
|
|
|
+ String uri = UriComponentsBuilder.fromUriString(url).queryParams(params).toUriString();
|
|
|
+ return webClient.get()
|
|
|
+ .uri(uri)
|
|
|
+ .accept(MediaType.APPLICATION_JSON)
|
|
|
+ .retrieve()
|
|
|
+ .bodyToMono(responseType)
|
|
|
+ .toFuture();
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <T> Mono<T> doPost(String url, Object request, Class<T> responseType) {
|
|
|
+ return webClient.post()
|
|
|
+ .uri(url)
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .accept(MediaType.APPLICATION_JSON)
|
|
|
+ .bodyValue(request)
|
|
|
+ .retrieve()
|
|
|
+ .bodyToMono(responseType);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static <T> Mono<T> doPut(String url, Object request, Class<T> responseType) {
|
|
|
+ return webClient.put()
|
|
|
+ .uri(url)
|
|
|
+ .contentType(MediaType.APPLICATION_JSON)
|
|
|
+ .accept(MediaType.APPLICATION_JSON)
|
|
|
+ .bodyValue(request)
|
|
|
+ .retrieve()
|
|
|
+ .bodyToMono(responseType);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Mono<Void> doDelete(String url) {
|
|
|
+ return webClient.delete()
|
|
|
+ .uri(url)
|
|
|
+ .retrieve()
|
|
|
+ .bodyToMono(Void.class);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|