package com.example.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.util.*;
@Slf4j
public class RestClientUtil {
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
public RestClientUtil(RestTemplate restTemplate, ObjectMapper objectMapper) {
this.restTemplate = restTemplate;
this.objectMapper = objectMapper;
}
public RequestBuilder request() {
return new RequestBuilder();
}
public class RequestBuilder {
private HttpMethod method = HttpMethod.GET;
private String url;
private Map<String, ?> urlParams = Collections.emptyMap();
private final Map<String, String> headers = new LinkedHashMap<>();
private Object body;
private MediaType contentType;
private TypeReference<?> responseType;
// 新增:form参数收集
private final MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>();
private RequestBuilder() {
headers.put(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
headers.put(HttpHeaders.ACCEPT_CHARSET, StandardCharsets.UTF_8.name());
}
public RequestBuilder method(HttpMethod method) {
this.method = method;
return this;
}
public RequestBuilder url(String url) {
this.url = url;
return this;
}
public RequestBuilder urlParams(Map<String, ?> urlParams) {
if (urlParams != null) {
this.urlParams = urlParams;
}
return this;
}
public RequestBuilder addHeader(String name, String value) {
if (name != null && value != null) {
headers.put(name, value);
}
return this;
}
public RequestBuilder headers(Map<String, String> headers) {
if (headers != null) {
this.headers.putAll(headers);
}
return this;
}
public RequestBuilder body(Object body) {
this.body = body;
return this;
}
public RequestBuilder contentType(MediaType contentType) {
this.contentType = contentType;
return this;
}
public <T> RequestBuilder responseType(TypeReference<T> responseType) {
this.responseType = responseType;
return this;
}
/**
* 新增:添加form单个参数,链式调用
*/
public RequestBuilder formParam(String key, String value) {
if (key != null && value != null) {
formParams.add(key, value);
}
return this;
}
public <T> T execute() {
if (url == null || url.isEmpty()) {
throw new IllegalArgumentException("请求URL不能为空");
}
if (responseType == null) {
throw new IllegalArgumentException("必须设置响应类型 responseType");
}
// 如果有formParams,优先使用form请求体,Content-Type自动设置
if (!formParams.isEmpty()) {
this.contentType = MediaType.APPLICATION_FORM_URLENCODED;
this.body = formParams;
}
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setAll(headers);
if (contentType != null) {
httpHeaders.setContentType(contentType);
}
httpHeaders.setAcceptCharset(Collections.singletonList(StandardCharsets.UTF_8));
HttpEntity<?> entity;
try {
if (body == null) {
entity = new HttpEntity<>(httpHeaders);
} else if (MediaType.APPLICATION_JSON.includes(contentType)) {
String jsonBody = body instanceof String ? (String) body : objectMapper.writeValueAsString(body);
entity = new HttpEntity<>(jsonBody, httpHeaders);
} else if (MediaType.APPLICATION_FORM_URLENCODED.includes(contentType)) {
if (!(body instanceof MultiValueMap)) {
throw new IllegalArgumentException("Form请求体必须是 MultiValueMap 类型");
}
entity = new HttpEntity<>(body, httpHeaders);
} else if (MediaType.TEXT_PLAIN.includes(contentType)) {
entity = new HttpEntity<>(Objects.toString(body), httpHeaders);
} else {
entity = new HttpEntity<>(body, httpHeaders);
}
} catch (JsonProcessingException e) {
log.error("请求体序列化异常", e);
throw new RestClientException("请求体序列化异常", e);
}
log.info("请求信息: method={}, url={}, urlParams={}, headers={}, body={}, contentType={}",
method, url, urlParams, headers, body, contentType);
try {
ResponseEntity<String> responseEntity = restTemplate.exchange(url, method, entity, String.class, urlParams);
log.info("响应状态码: {}", responseEntity.getStatusCodeValue());
if (responseEntity.hasBody()) {
log.info("响应体: {}", responseEntity.getBody());
} else {
log.warn("响应无内容");
}
if (!responseEntity.getStatusCode().is2xxSuccessful()) {
throw new RestClientException("HTTP请求失败,状态码:" + responseEntity.getStatusCodeValue());
}
String respBody = responseEntity.getBody();
if (respBody == null || respBody.isEmpty()) {
return null;
}
@SuppressWarnings("unchecked")
T result = (T) objectMapper.readValue(respBody, responseType);
return result;
} catch (Exception e) {
log.error("请求执行异常", e);
throw new RestClientException("请求执行异常", e);
}
}
}
}