2025-07-07 07:08:01 +08:00

176 lines
6.3 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.knowledge.base.infrastructure.util;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* OkHttp封装的 HTTP 客户端工具类(支持 JSON POST、GET、Token注入、泛型反序列化、流式请求
*/
@Slf4j
@Component
public class HttpHelper {
private final OkHttpClient client;
private final ObjectMapper objectMapper;
public HttpHelper() {
this.client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(300, TimeUnit.SECONDS)
.build();
this.objectMapper = new ObjectMapper();
}
/**
* 发送 POST JSON 请求,自动反序列化为 Map
*/
public Map<String, Object> postJson(String url, Map<String, Object> body, String token) throws IOException {
Request request = buildJsonRequest(url, body, token, "POST");
return executeJson(request);
}
/**
* 发送 GET 请求,自动反序列化为 Map
*/
public Map<String, Object> get(String url, String token) throws IOException {
Request request = buildJsonRequest(url, null, token, "GET");
return executeJson(request);
}
/**
* 流式 POST 请求,返回 Response 实例,调用方负责关闭 response.body().close()
*/
public Response postStream(String url, Map<String, Object> body, String token) throws IOException {
String json = objectMapper.writeValueAsString(body);
RequestBody requestBody = RequestBody.create(json, MediaType.get("application/json; charset=utf-8"));
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", token)
.addHeader("Accept", "text/event-stream")
.addHeader("Connection", "keep-alive")
.post(requestBody)
.build();
return client.newCall(request).execute();
}
/**
* 构建 JSON 类型的 Request 请求
*/
private Request buildJsonRequest(String url, Map<String, Object> body, String token, String method) throws IOException {
RequestBody requestBody = null;
if (body != null) {
String json = objectMapper.writeValueAsString(body);
requestBody = RequestBody.create(json, MediaType.get("application/json; charset=utf-8"));
}
Request.Builder builder = new Request.Builder().url(url);
if (token != null && !token.isBlank()) {
builder.header("Authorization", "Bearer " + token);
}
switch (method.toUpperCase()) {
case "POST":
builder.post(requestBody != null ? requestBody : RequestBody.create(new byte[0]));
break;
case "GET":
builder.get();
break;
case "PUT":
builder.put(requestBody);
break;
case "DELETE":
if (requestBody != null) {
builder.delete(requestBody);
} else {
builder.delete();
}
break;
default:
throw new IllegalArgumentException("不支持的请求方法:" + method);
}
return builder.build();
}
/**
* 通用 HTTP 请求方法,支持任意 method、headers、请求体自动反序列化返回
*
* @param url 请求地址
* @param method 请求方法,如 GET、POST、PUT、DELETE
* @param headers 请求头(可选,可为 null
* @param body 请求体对象(可选,可为 null
* @param responseType 返回类型(例如 Map.class
* @param <T> 泛型类型
* @return 反序列化后的对象
* @throws IOException 请求失败或 JSON 解析异常
*/
/**
* 通用 HTTP 请求方法,支持任意 method、headers、请求体支持泛型 TypeReference<T> 返回Jackson
*/
public <T> T exchange(String url, String method, Map<String, String> headers, Object body, TypeReference<T> typeRef) throws IOException {
RequestBody requestBody = null;
if (body != null) {
String json = objectMapper.writeValueAsString(body);
requestBody = RequestBody.create(json, MediaType.get("application/json; charset=utf-8"));
}
Request.Builder builder = new Request.Builder().url(url);
if (headers != null) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
builder.addHeader(entry.getKey(), entry.getValue());
}
}
switch (method.toUpperCase()) {
case "POST":
builder.post(requestBody != null ? requestBody : RequestBody.create(new byte[0]));
break;
case "PUT":
builder.put(requestBody != null ? requestBody : RequestBody.create(new byte[0]));
break;
case "DELETE":
builder.delete(requestBody != null ? requestBody : null);
break;
case "GET":
default:
builder.get();
break;
}
Request request = builder.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("请求失败: " + response.code() + " - " + response.message());
}
String json = response.body().string();
return objectMapper.readValue(json, typeRef);
}
}
/**
* 执行请求并解析为 Map
*/
private Map<String, Object> executeJson(Request request) throws IOException {
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("请求失败: " + response.code() + " - " + response.message());
}
String json = response.body().string();
return objectMapper.readValue(json, new TypeReference<>() {});
}
}
}