diff --git a/txw-common/.gitignore b/txw-common/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/txw-common/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/txw-common/README.md b/txw-common/README.md
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/txw-common/README.md
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/txw-common/pom.xml b/txw-common/pom.xml
new file mode 100644
index 0000000..e37ddf8
--- /dev/null
+++ b/txw-common/pom.xml
@@ -0,0 +1,78 @@
+
+
+ 4.0.0
+
+ com.css.ggzc
+ ggzc-framework-dependencies
+ 1.0.0-SNAPSHOT
+
+ txw-common
+ com.css.txw
+ 1.0.0-SNAPSHOT
+ ${project.artifactId}
+ txw-common
+
+ ${project.artifactId}
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.3.1
+
+
+
+
+
+
+
+ codingcorp-qyd_repo-mvn_public
+ mvn_public
+ http://codingcorp-maven.pkg.codingstd.xc01.cloud.sat.tax/repository/qyd_repo/mvn_public/
+
+
+
+
+
+ com.css.ggzc
+ ggzc-framework-starter
+ 1.0.0-SNAPSHOT
+ pom
+ import
+
+
+
+
+
+
+
+ com.css.ggzc
+ ggzc-framework-starter-web
+
+
+
+ com.css.ggzc
+ ggzc-framework-starter-common
+
+
+
+ com.css.ggzc
+ ggzc-framework-starter-cache
+
+
+
+ com.css.ggzc
+ ggzc-framework-starter-mybatis
+
+
+
+ com.css.ggzc
+ ggzc-framework-starter-cache
+
+
+
+ com.alibaba
+ easyexcel
+
+
+
diff --git a/txw-common/settings.xml b/txw-common/settings.xml
new file mode 100644
index 0000000..e089e4a
--- /dev/null
+++ b/txw-common/settings.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+ codingcorp-qyd_repo-mvn_public
+ coding-user
+ coding-pwd
+
+
+
+
+
+
+ Repository Proxy
+
+ true
+
+
+
+
+ codingcorp-qyd_repo-mvn_public
+ mvn_public
+ http://codingcorp-maven.pkg.codingstd.xc01.cloud.sat.tax/repository/qyd_repo/mvn_public/
+
+ true
+
+
+ true
+ always
+
+
+
+
+
+ codingcorp-qyd_repo-mvn_public
+
+ true
+
+
+ true
+
+ http://codingcorp-maven.pkg.codingstd.xc01.cloud.sat.tax/repository/qyd_repo/mvn_public/
+
+
+
+
+
+
+
+ codingcorp-qyd_repo-mvn_public
+
+ central
+ mvn_public
+ http://codingcorp-maven.pkg.codingstd.xc01.cloud.sat.tax/repository/qyd_repo/mvn_public/
+
+
+
diff --git a/txw-common/src/main/java/com/css/txw/common/configuration/SMSConfig.java b/txw-common/src/main/java/com/css/txw/common/configuration/SMSConfig.java
new file mode 100644
index 0000000..c7af893
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/configuration/SMSConfig.java
@@ -0,0 +1,30 @@
+package com.css.txw.common.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @Description: 短信配置
+ * @Autor wujy
+ * @Date 2025/11/21
+ */
+@Data
+@RefreshScope
+@Configuration
+@ConfigurationProperties(prefix = "css.txw.sms")
+public class SMSConfig {
+
+ private String host;
+
+ //app:请求应用的唯一标识,例如:OA
+ private String app;
+
+ //key:双方系统约定的密钥
+ private String key;
+
+ //短信内容模版
+ private String template;
+
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/configuration/SMSConstant.java b/txw-common/src/main/java/com/css/txw/common/configuration/SMSConstant.java
new file mode 100644
index 0000000..169459f
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/configuration/SMSConstant.java
@@ -0,0 +1,11 @@
+package com.css.txw.common.configuration;
+
+/**
+ * @Description: 短信服务相关
+ * @Autor wujy
+ * @Date 2025/11/21
+ */
+public class SMSConstant {
+ public static final String SEND_SM_URI = "/nbsgd/messageApi/smsmessage/send";
+
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/configuration/TxwCommonConfiguration.java b/txw-common/src/main/java/com/css/txw/common/configuration/TxwCommonConfiguration.java
new file mode 100644
index 0000000..9ea963b
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/configuration/TxwCommonConfiguration.java
@@ -0,0 +1,10 @@
+package com.css.txw.common.configuration;
+
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+
+@AutoConfiguration
+@ComponentScan("com.css.txw.common")
+public class TxwCommonConfiguration {
+
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/net/HttpHutoolImpl.java b/txw-common/src/main/java/com/css/txw/common/net/HttpHutoolImpl.java
new file mode 100644
index 0000000..465bd22
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/net/HttpHutoolImpl.java
@@ -0,0 +1,87 @@
+package com.css.txw.common.net;
+
+import cn.hutool.http.Header;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class HttpHutoolImpl implements IHttpService {
+
+ public final static String CONTENT_TYPE_JSON = "application/json";
+ public final static String CONTENT_TYPE_FORM = "multipart/form-data;";
+ public final static String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36";
+ public final static String ACCEPT = "application/json, text/plain, */*";
+
+ public HttpResponse get(String url) {
+ HttpRequest request = HttpUtil.createGet(url);
+ return this.executeReq(request);
+ }
+
+ @Override
+ public HttpResponse get(String url, Map params) {
+ HttpRequest request = HttpUtil.createGet(url);
+ request.form(params);
+ return this.executeReq(request);
+ }
+
+ @Override
+ public HttpResponse postForm(String url, Map form) {
+ HttpRequest request = HttpUtil.createPost(url);
+ request.form(form);
+ return this.executeReq(request, CONTENT_TYPE_FORM);
+ }
+
+ @Override
+ public HttpResponse postForm(String url, Map form, Map files) {
+ HttpRequest request = HttpUtil.createPost(url);
+ request.form(form);
+ if (null != files) {
+ for (String key : files.keySet()) {
+ request.form(key, files.get(key), files.get(key).getName());
+ }
+ request.timeout(1000 * 60);
+ }
+ return this.executeReq(request, CONTENT_TYPE_FORM);
+ }
+
+ @Override
+ public T postJson(String url, String body, Class resType) {
+ HttpRequest request = HttpUtil.createPost(url);
+ if (StringUtils.isNotBlank(body)) {
+ request.body(body);
+ }
+ try {
+ HttpResponse response = this.executeReq(request);
+ if (response.isOk()) {
+ String resBody = response.body();
+ log.info("Hutool http response body: {}", resBody);
+ return new Gson().fromJson(resBody, resType);
+ } else {
+ log.info("请求失败,状态码:{}", response.getStatus());
+ }
+ } catch (Exception e) {
+ log.error("error:", e);
+ }
+ return null;
+ }
+
+ private HttpResponse executeReq(HttpRequest request) {
+ return this.executeReq(request, CONTENT_TYPE_JSON);
+ }
+
+ private HttpResponse executeReq(HttpRequest request,String contentType) {
+ request.contentType(contentType).header(Header.USER_AGENT, USER_AGENT).header(Header.ACCEPT, ACCEPT);
+ return request.execute();
+ }
+
+
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/net/IHttpService.java b/txw-common/src/main/java/com/css/txw/common/net/IHttpService.java
new file mode 100644
index 0000000..3539dda
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/net/IHttpService.java
@@ -0,0 +1,17 @@
+package com.css.txw.common.net;
+
+import cn.hutool.http.HttpResponse;
+
+import java.io.File;
+import java.util.Map;
+
+public interface IHttpService {
+
+ HttpResponse get(String url, Map params);
+
+ HttpResponse postForm(String url, Map form);
+
+ HttpResponse postForm(String url, Map form, Map files);
+
+ T postJson(String url, String body, Class resType);
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/pojo/ExcelVerifyInfo.java b/txw-common/src/main/java/com/css/txw/common/pojo/ExcelVerifyInfo.java
new file mode 100644
index 0000000..a6587bd
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/pojo/ExcelVerifyInfo.java
@@ -0,0 +1,10 @@
+package com.css.txw.common.pojo;
+
+import lombok.Data;
+
+@Data
+public class ExcelVerifyInfo {
+ private String errorMsg;
+ private Integer rowNum;
+
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMCaptchaDTO.java b/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMCaptchaDTO.java
new file mode 100644
index 0000000..44c1a3d
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMCaptchaDTO.java
@@ -0,0 +1,17 @@
+package com.css.txw.common.pojo.dto.sms;
+
+import lombok.Data;
+
+/**
+ * @Description: 发送短信验证码,根据配置模版格式发送验证码
+ * @Autor wujy
+ * @Date 2025/11/21
+ */
+@Data
+public class SMCaptchaDTO {
+ //接收手机号码 "1311111111,1352222222"
+ private String receiveMobile;
+ //验证码
+ private String captcha;
+
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMSReqDTO.java b/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMSReqDTO.java
new file mode 100644
index 0000000..34665a9
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMSReqDTO.java
@@ -0,0 +1,19 @@
+package com.css.txw.common.pojo.dto.sms;
+
+import lombok.Data;
+
+/**
+ * @Description: 短信发送报文
+ * @Autor wujy
+ * @Date 2025/11/21
+ */
+@Data
+public class SMSReqDTO {
+ //接收手机号码 "1311111111,1352222222"
+ private String receiveMobile;
+ //短信内容
+ private String content;
+ //发送时间, 自定义发送时间,空或小于当前时间立即发送
+ private String sendTime;
+
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMSResDTO.java b/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMSResDTO.java
new file mode 100644
index 0000000..f30cccb
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/pojo/dto/sms/SMSResDTO.java
@@ -0,0 +1,17 @@
+package com.css.txw.common.pojo.dto.sms;
+
+import lombok.Data;
+
+/**
+ * @Description: 短信服务响应报文
+ * @Autor wujy
+ * @Date 2025/11/21
+ */
+@Data
+public class SMSResDTO {
+ private String code;//返回代码值
+ private String type;//枚举型,包括:success、error
+ private String token;//请求服务时传递的唯一标识UUID
+ private String message;//返回消息
+ private T data;//返回数据内容
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/service/ISMService.java b/txw-common/src/main/java/com/css/txw/common/service/ISMService.java
new file mode 100644
index 0000000..b3447cc
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/service/ISMService.java
@@ -0,0 +1,9 @@
+package com.css.txw.common.service;
+
+import com.css.txw.common.pojo.dto.sms.SMCaptchaDTO;
+import com.css.txw.common.pojo.dto.sms.SMSResDTO;
+
+public interface ISMService {
+
+ SMSResDTO sendCaptcha(String phone, String code);
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/service/impl/SMServiceImpl.java b/txw-common/src/main/java/com/css/txw/common/service/impl/SMServiceImpl.java
new file mode 100644
index 0000000..e46b7d2
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/service/impl/SMServiceImpl.java
@@ -0,0 +1,62 @@
+package com.css.txw.common.service.impl;
+
+import cn.hutool.crypto.digest.DigestUtil;
+import com.css.ggzc.framework.common.util.gy.GyUtils;
+import com.css.txw.common.configuration.SMSConfig;
+import com.css.txw.common.configuration.SMSConstant;
+import com.css.txw.common.net.IHttpService;
+import com.css.txw.common.pojo.dto.sms.SMSReqDTO;
+import com.css.txw.common.pojo.dto.sms.SMSResDTO;
+import com.css.txw.common.service.ISMService;
+import com.css.txw.common.util.TxwHttpUtils;
+import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+/**
+ * @Description: 短信服务
+ * @Autor wujy
+ * @Date 2025/11/21
+ */
+@Slf4j
+@Service
+public class SMServiceImpl implements ISMService {
+
+ @Resource
+ private SMSConfig config;
+ @Resource
+ private IHttpService httpService;
+
+ //发送短信验证码
+ @Override
+ public SMSResDTO sendCaptcha(String phone, String code) {
+ //时间戳,如:1611472667681
+ long timestamp = new Date().getTime();
+ String app = config.getApp();
+ //请求唯一标识,使用UUID
+ String token = GyUtils.getUuid();
+ //校验码,使用timestamp+app+token+key进行MD5加密后的字符再进行性一次加密最后形成校验码
+ String vcode = DigestUtil.md5Hex(DigestUtil.md5Hex(timestamp + app + token + config.getKey()));
+ String url = config.getHost() + SMSConstant.SEND_SM_URI + "?timestamp=" + timestamp + "&token=" + token +
+ "&app=" + app + "&vcode=" + vcode;
+ //构建报文
+ String content = String.format(config.getTemplate(), code);
+ SMSReqDTO smReqDTO = new SMSReqDTO();
+ smReqDTO.setReceiveMobile(phone);
+ smReqDTO.setContent(content);
+ //发送
+ SMSResDTO res = httpService.postJson(url, new Gson().toJson(smReqDTO), SMSResDTO.class);
+ log.info("短信发送 Response {}, code:{} message:{}", res.getType(),res.getCode(), res.getMessage());
+ return res;
+ }
+
+ // 发送其他短信
+ public String sendMsg(SMSReqDTO reqDTO) {
+ // to do something
+ return null;
+ }
+
+}
diff --git a/txw-common/src/main/java/com/css/txw/common/util/TxwHttpUtils.java b/txw-common/src/main/java/com/css/txw/common/util/TxwHttpUtils.java
new file mode 100644
index 0000000..ba35261
--- /dev/null
+++ b/txw-common/src/main/java/com/css/txw/common/util/TxwHttpUtils.java
@@ -0,0 +1,289 @@
+package com.css.txw.common.util;
+
+import com.css.ggzc.framework.cache.utils.XtcsUtils;
+import com.css.ggzc.framework.common.util.gy.GyUtils;
+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.http.client.SimpleClientHttpRequestFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.net.Proxy;
+import java.util.Map;
+
+/**
+ * 基于Spring Cloud Alibaba的HTTP工具类
+ * 支持GET、POST、PUT、DELETE请求,兼容HTTP/HTTPS协议
+ * 支持Nacos服务发现和负载均衡
+ * 版本:Spring Cloud Alibaba 2021.0.6.0
+ */
+@Slf4j
+@Component
+public class TxwHttpUtils {
+
+ @Resource
+ private RestTemplate restTemplate = new RestTemplate();
+
+
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ @PostConstruct
+ public void init() {
+ log.info("SpringCloudAlibabaHttpUtil initialized successfully with Spring Cloud Alibaba 2021.0.6.0");
+ }
+
+ // ========== GET请求方法 ==========
+
+ /**
+ * GET请求 - 直接URL调用
+ */
+ public T get(String url, Class responseType) {
+ return get(url, null, responseType, null);
+ }
+
+ public T get(String url, Map params, Class responseType) {
+ return get(url, params, responseType, null);
+ }
+
+ public T get(String url, Map params, Class responseType,
+ Map headers) {
+ try {
+ HttpEntity> entity = createHttpEntity(null, headers);
+ ResponseEntity response = restTemplate.exchange(
+ buildUrlWithParams(url, params),
+ HttpMethod.GET,
+ entity,
+ responseType
+ );
+ return handleResponse(response);
+ } catch (Exception e) {
+ log.error("GET请求失败, url: {}", url, e);
+ throw new RuntimeException("HTTP请求失败: " + e.getMessage(), e);
+ }
+ }
+
+ // ========== POST请求方法 ==========
+
+ /**
+ * POST请求 - 直接URL调用
+ */
+ public T post(String url, Object requestBody, Class responseType) {
+ return post(url, requestBody, responseType, null);
+ }
+
+ public T post(String url, Object requestBody, Class responseType,
+ Map headers) {
+ try {
+ HttpEntity> entity = createHttpEntity(requestBody, headers);
+ ResponseEntity response = restTemplate.exchange(
+ url,
+ HttpMethod.POST,
+ entity,
+ responseType
+ );
+ return handleResponse(response);
+ } catch (Exception e) {
+ log.error("POST请求失败, url: {}", url, e);
+ throw new RuntimeException("HTTP请求失败: " + e.getMessage(), e);
+ }
+ }
+
+ // ========== PUT请求方法 ==========
+
+ /**
+ * PUT请求 - 直接URL调用
+ */
+ public T put(String url, Object requestBody, Class responseType) {
+ return put(url, requestBody, responseType, null);
+ }
+
+ public T put(String url, Object requestBody, Class responseType,
+ Map headers) {
+ try {
+ HttpEntity> entity = createHttpEntity(requestBody, headers);
+ ResponseEntity response = restTemplate.exchange(
+ url,
+ HttpMethod.PUT,
+ entity,
+ responseType
+ );
+ return handleResponse(response);
+ } catch (Exception e) {
+ log.error("PUT请求失败, url: {}", url, e);
+ throw new RuntimeException("HTTP请求失败: " + e.getMessage(), e);
+ }
+ }
+
+ // ========== DELETE请求方法 ==========
+
+ /**
+ * DELETE请求 - 直接URL调用
+ */
+ public T delete(String url, Class responseType) {
+ return delete(url, null, responseType, null);
+ }
+
+ public T delete(String url, Map params, Class responseType) {
+ return delete(url, params, responseType, null);
+ }
+
+ public T delete(String url, Map params, Class responseType,
+ Map headers) {
+ try {
+ HttpEntity> entity = createHttpEntity(null, headers);
+ ResponseEntity response = restTemplate.exchange(
+ buildUrlWithParams(url, params),
+ HttpMethod.DELETE,
+ entity,
+ responseType
+ );
+ return handleResponse(response);
+ } catch (Exception e) {
+ log.error("DELETE请求失败, url: {}", url, e);
+ throw new RuntimeException("HTTP请求失败: " + e.getMessage(), e);
+ }
+ }
+
+ // ========== 通用请求方法 ==========
+
+ /**
+ * 通用请求方法
+ */
+ public T exchange(String url, HttpMethod method, Object requestBody,
+ Map headers, Class responseType) {
+ try {
+ ResponseEntity response;
+ RestTemplate restTemplateWithProxy = createRestTemplateWithProxy();
+ HttpEntity> entity = createHttpEntity(requestBody, headers);
+ if (GyUtils.isNotNull(restTemplateWithProxy)) {
+ response = restTemplateWithProxy.exchange(url, method, entity, responseType);
+ } else {
+ response = restTemplate.exchange(url, method, entity, responseType);
+ }
+ return handleResponse(response);
+ } catch (Exception e) {
+ log.error("{}请求失败, url: {}", method.name(), url, e);
+ throw new RuntimeException("HTTP请求失败: " + e.getMessage(), e);
+ }
+ }
+
+ // ========== 辅助方法 ==========
+
+ /**
+ * 构建带参数的URL
+ */
+ private String buildUrlWithParams(String url, Map params) {
+ if (params == null || params.isEmpty()) {
+ return url;
+ }
+
+ StringBuilder urlBuilder = new StringBuilder(url);
+ boolean hasQuery = url.contains("?");
+
+ for (Map.Entry entry : params.entrySet()) {
+ if (entry.getValue() == null) continue;
+
+ if (!hasQuery) {
+ urlBuilder.append("?");
+ hasQuery = true;
+ } else {
+ urlBuilder.append("&");
+ }
+
+ urlBuilder.append(entry.getKey())
+ .append("=")
+ .append(encodeParam(entry.getValue().toString()));
+ }
+
+ return urlBuilder.toString();
+ }
+
+ /**
+ * 参数编码
+ */
+ private String encodeParam(String param) {
+ try {
+ return java.net.URLEncoder.encode(param, "UTF-8");
+ } catch (Exception e) {
+ log.warn("参数编码失败: {}", param, e);
+ return param;
+ }
+ }
+
+ /**
+ * 创建HTTP实体
+ */
+ private HttpEntity> createHttpEntity(Object requestBody, Map headers) {
+ HttpHeaders httpHeaders = new HttpHeaders();
+
+ // 设置默认头
+ if (requestBody instanceof MultiValueMap) {
+ httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+ } else if (requestBody != null) {
+ httpHeaders.setContentType(MediaType.APPLICATION_JSON);
+ }
+
+ // 添加自定义头
+ if (headers != null) {
+ headers.forEach(httpHeaders::add);
+ }
+
+ return new HttpEntity<>(requestBody, httpHeaders);
+ }
+
+ /**
+ * 处理响应
+ */
+ private T handleResponse(ResponseEntity response) {
+ if (response.getStatusCode().is2xxSuccessful()) {
+ return response.getBody();
+ } else {
+ String errorMsg = String.format("HTTP请求失败, 状态码: %d, 响应: %s",
+ response.getStatusCodeValue(), response.getBody());
+ log.error(errorMsg);
+ throw new RuntimeException(errorMsg);
+ }
+ }
+
+ /**
+ * 将对象转换为MultiValueMap(用于表单提交)
+ */
+ public MultiValueMap convertToFormData(Object obj) {
+ try {
+ MultiValueMap formData = new LinkedMultiValueMap<>();
+ Map map = objectMapper.convertValue(obj, new TypeReference