阿奇索自动发货接入接口
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
yudao-ui-admin CI / build (14.x) (push) Has been cancelled
yudao-ui-admin CI / build (16.x) (push) Has been cancelled
Some checks failed
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
yudao-ui-admin CI / build (14.x) (push) Has been cancelled
yudao-ui-admin CI / build (16.x) (push) Has been cancelled
This commit is contained in:
@@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
* 全局错误码枚举
|
||||
* 0-999 系统异常编码保留
|
||||
*
|
||||
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
|
||||
* 一般情况下,使用 HTTP 响应状态码 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status">...</a>
|
||||
* 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
|
||||
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
|
||||
*
|
||||
|
@@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.kfc.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "agiso")
|
||||
@Configuration
|
||||
public class AgisoConfig {
|
||||
|
||||
private String appid;
|
||||
|
||||
private String appsecret;
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.kfc.config;
|
||||
|
||||
import okhttp3.ConnectionPool;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
/**
|
||||
OkHttp 配置类,用于创建并注册 OkHttpClient 实例到 Spring 容器
|
||||
*/
|
||||
@Configuration
|
||||
public class OkHttpConfig {
|
||||
/**
|
||||
定义 OkHttpClient 的 bean,设置超时时间和连接池等参数
|
||||
*/
|
||||
@Bean
|
||||
public OkHttpClient okHttpClient () {
|
||||
// 连接池配置:最大空闲连接数 5 个,连接空闲超时 5 分钟
|
||||
ConnectionPool connectionPool = new ConnectionPool (5, 5, TimeUnit.MINUTES);
|
||||
return new OkHttpClient.Builder ()
|
||||
.connectTimeout (30, TimeUnit.SECONDS)
|
||||
.readTimeout (30, TimeUnit.SECONDS)
|
||||
.writeTimeout (30, TimeUnit.SECONDS)
|
||||
.connectionPool (connectionPool)
|
||||
.retryOnConnectionFailure (true)
|
||||
.build ();
|
||||
}
|
||||
}
|
@@ -44,7 +44,6 @@ public class AgisoAuthCallbackController {
|
||||
|
||||
@GetMapping("/get/code-url")
|
||||
@Operation(summary = "生成阿奇索code认证url")
|
||||
@PermitAll
|
||||
public CommonResult<String> getCodeUrl() {
|
||||
return success(agisoAuthService.generateAuthUrl());
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ import lombok.Data;
|
||||
* 授权成功后返回的AccessToken相关数据实体类
|
||||
*/
|
||||
@Data
|
||||
public class AccessTokenData {
|
||||
public class AgisoData {
|
||||
|
||||
/**
|
||||
* 平台标识
|
@@ -7,7 +7,7 @@ import lombok.Data;
|
||||
* 换取AccessToken的完整响应实体类
|
||||
*/
|
||||
@Data
|
||||
public class AccessTokenResponse {
|
||||
public class AgisoResponse {
|
||||
|
||||
/**
|
||||
* 操作是否成功
|
||||
@@ -31,5 +31,5 @@ public class AccessTokenResponse {
|
||||
* 详细数据(成功时返回)
|
||||
*/
|
||||
@JsonProperty("Data")
|
||||
private AccessTokenData data;
|
||||
private AgisoData data;
|
||||
}
|
@@ -53,4 +53,7 @@ public interface ErrorCodeConstants {
|
||||
|
||||
ErrorCode RESPONSE_IS_EMPTY = new ErrorCode(2_001_013_000,"响应体为空");
|
||||
ErrorCode TOKEN_IS_EMPTY = new ErrorCode(2_001_013_001,"响应数据中未包含有效的Token");
|
||||
ErrorCode STATE_NOT_VALID = new ErrorCode(2_001_013_002,"回调失败:state参数无效或已过期");
|
||||
ErrorCode TOKEN_AUTH_FAILED = new ErrorCode(2_001_013_003,"认证失败:token令牌无效或已过期");
|
||||
ErrorCode USER_AUTH_FAILED = new ErrorCode(2_001_013_004,"用户授权失败");
|
||||
}
|
||||
|
@@ -1,9 +1,26 @@
|
||||
package cn.iocoder.yudao.module.kfc.service.agiso;
|
||||
|
||||
import cn.iocoder.yudao.module.kfc.controller.admin.agisoproxy.vo.AgisoResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface AgisoAuthService {
|
||||
|
||||
String generateAuthUrl();
|
||||
|
||||
String authAndGetAccessToken(String code, String state, String error);
|
||||
|
||||
AgisoResponse execute(String url, String method, Map<String, String> params, String sellerOpenUid) throws IOException, NoSuchAlgorithmException;
|
||||
|
||||
AgisoResponse doPost(String url, Map<String, String> params, String sellerOpenUid) throws NoSuchAlgorithmException;
|
||||
|
||||
AgisoResponse doGet(String url, Map<String, String> params, String sellerOpenUid) throws NoSuchAlgorithmException;
|
||||
|
||||
AgisoResponse autoShipment(List<String> tids, String sellerOpenUid) throws NoSuchAlgorithmException;
|
||||
|
||||
String sign(Map<String, String> params, String appSecret)
|
||||
throws NoSuchAlgorithmException;
|
||||
}
|
||||
|
@@ -1,40 +1,41 @@
|
||||
package cn.iocoder.yudao.module.kfc.service.agiso;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.iocoder.yudao.module.kfc.controller.admin.agisoproxy.vo.AccessTokenData;
|
||||
import cn.iocoder.yudao.module.kfc.controller.admin.agisoproxy.vo.AccessTokenResponse;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import cn.iocoder.yudao.module.kfc.config.AgisoConfig;
|
||||
import cn.iocoder.yudao.module.kfc.controller.admin.agisoproxy.vo.AgisoData;
|
||||
import cn.iocoder.yudao.module.kfc.controller.admin.agisoproxy.vo.AgisoResponse;
|
||||
import cn.iocoder.yudao.module.kfc.utils.HttpUtils;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import okhttp3.*;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.kfc.enums.ErrorCodeConstants.RESPONSE_IS_EMPTY;
|
||||
import static cn.iocoder.yudao.module.kfc.enums.ErrorCodeConstants.TOKEN_IS_EMPTY;
|
||||
import static cn.iocoder.yudao.module.kfc.enums.ErrorCodeConstants.*;
|
||||
import static software.amazon.awssdk.http.HttpStatusCode.BAD_REQUEST;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AgisoAuthServiceImpl implements AgisoAuthService {
|
||||
|
||||
@Value("${agiso.appid}")
|
||||
private String APPID;
|
||||
@Value("${agiso.appsecret}")
|
||||
private String APPSECRET;
|
||||
@Resource
|
||||
private AgisoConfig agisoConfig;
|
||||
|
||||
// Redis中存储state的前缀,过期时间10分钟(授权流程通常较短)
|
||||
// Redis中存储state的前缀,过期时间10分钟
|
||||
private static final String STATE_REDIS_KEY_PREFIX = "agiso:auth:state:";
|
||||
private static final String TOKEN_REDIS_KEY_PREFIX = "agiso:token:";
|
||||
private static final long STATE_EXPIRE_MINUTES = 10;
|
||||
private static final String AUTO_SHIPMENTS_URL = "http://gw.api.agiso.com/alds/Trade/AldsProcessTrades";
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@@ -46,7 +47,7 @@ public class AgisoAuthServiceImpl implements AgisoAuthService {
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 生成授权链接(新增方法,用于发起授权)
|
||||
* 生成授权链接
|
||||
*/
|
||||
@Override
|
||||
public String generateAuthUrl() {
|
||||
@@ -56,7 +57,7 @@ public class AgisoAuthServiceImpl implements AgisoAuthService {
|
||||
redisTemplate.opsForValue()
|
||||
.set(STATE_REDIS_KEY_PREFIX + state, "VALID", STATE_EXPIRE_MINUTES, TimeUnit.MINUTES);
|
||||
// 3. 拼接授权URL
|
||||
return "https://alds.agiso.com/authorize.aspx?appId=" + APPID + "&state=" + state;
|
||||
return "https://alds.agiso.com/authorize.aspx?appId=" + agisoConfig.getAppid() + "&state=" + state;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,7 +69,7 @@ public class AgisoAuthServiceImpl implements AgisoAuthService {
|
||||
String redisKey = STATE_REDIS_KEY_PREFIX + state;
|
||||
if (!redisTemplate.hasKey(redisKey)) {
|
||||
log.warn("授权回调失败,state校验不通过,state={}", state);
|
||||
return "回调失败:state参数无效或已过期";
|
||||
throw exception(STATE_NOT_VALID);
|
||||
}
|
||||
// 校验通过后删除state,防止重复使用
|
||||
redisTemplate.delete(redisKey);
|
||||
@@ -76,33 +77,34 @@ public class AgisoAuthServiceImpl implements AgisoAuthService {
|
||||
// 2. 处理授权失败场景
|
||||
if (error != null) {
|
||||
log.warn("用户授权失败,error={}", error);
|
||||
return "授权失败:" + error;
|
||||
throw exception(USER_AUTH_FAILED);
|
||||
}
|
||||
|
||||
// 3. 处理授权成功场景
|
||||
if (code != null) {
|
||||
try {
|
||||
String accessToken = getAccessToken(code, state);
|
||||
log.info("授权成功,AccessToken已存储到redis");
|
||||
return "success";
|
||||
} catch (Exception e) {
|
||||
log.error("换取AccessToken失败,code={}", code, e);
|
||||
return "换取AccessToken失败:" + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return "err:回调参数异常";
|
||||
//异步执行,不阻塞回调线程
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
String accessToken = generateAccessToken(code, state);
|
||||
log.info("授权成功,AccessToken已存储到redis");
|
||||
} catch (Exception e) {
|
||||
log.error("换取AccessToken失败,code={}", code, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
return "success";
|
||||
}
|
||||
|
||||
/**
|
||||
* 用授权码code换取AccessToken
|
||||
*/
|
||||
private String getAccessToken(String code, String state) throws IOException {
|
||||
private String generateAccessToken(String code, String state) throws IOException {
|
||||
// 1. 构建请求URL
|
||||
HttpUrl url = Objects.requireNonNull(HttpUrl.parse("https://alds.agiso.com/auth/token")).newBuilder()
|
||||
.addQueryParameter("code", code)
|
||||
.addQueryParameter("appId", APPID)
|
||||
.addQueryParameter("secret", APPSECRET)
|
||||
.addQueryParameter("appId", agisoConfig.getAppid())
|
||||
.addQueryParameter("secret", agisoConfig.getAppsecret())
|
||||
.addQueryParameter("state", state) // 使用回调的state,保持一致
|
||||
.build();
|
||||
log.debug("请求AccessToken的URL:{}", url);
|
||||
@@ -128,7 +130,7 @@ public class AgisoAuthServiceImpl implements AgisoAuthService {
|
||||
}
|
||||
|
||||
// 6. 解析响应
|
||||
AccessTokenResponse tokenResponse = objectMapper.readValue(responseBody, AccessTokenResponse.class);
|
||||
AgisoResponse tokenResponse = objectMapper.readValue(responseBody, AgisoResponse.class);
|
||||
if (!tokenResponse.isSuccess()) {
|
||||
throw new RuntimeException(String.format(
|
||||
"接口返回失败,错误码:%d,错误信息:%s",
|
||||
@@ -138,13 +140,13 @@ public class AgisoAuthServiceImpl implements AgisoAuthService {
|
||||
}
|
||||
|
||||
// 7. 提取Token和相关信息
|
||||
AccessTokenData data = tokenResponse.getData();
|
||||
AgisoData data = tokenResponse.getData();
|
||||
if (data == null || data.getToken() == null || data.getToken().isEmpty()) {
|
||||
throw exception(TOKEN_IS_EMPTY);
|
||||
}
|
||||
|
||||
// 8. 缓存Token
|
||||
String cacheKey = "agiso:token:" + data.getSellerOpenUid();
|
||||
String cacheKey = TOKEN_REDIS_KEY_PREFIX + data.getSellerOpenUid();
|
||||
redisTemplate.opsForValue()
|
||||
.set(cacheKey, data.getToken(), data.getExpiresIn(), TimeUnit.SECONDS);
|
||||
log.info("AccessToken缓存成功,商家ID:{},过期时间:{}秒", data.getSellerOpenUid(), data.getExpiresIn());
|
||||
@@ -152,4 +154,105 @@ public class AgisoAuthServiceImpl implements AgisoAuthService {
|
||||
return data.getToken();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgisoResponse execute(String url, String method, Map<String, String> params, String sellerOpenUid) throws NoSuchAlgorithmException {
|
||||
|
||||
if (params == null) params = new HashMap<>();
|
||||
|
||||
//从redis获取accessToken
|
||||
String accessToken = redisTemplate.opsForValue().get(TOKEN_REDIS_KEY_PREFIX + sellerOpenUid);
|
||||
if (accessToken == null) throw exception(TOKEN_AUTH_FAILED);
|
||||
|
||||
//构建公共请求参数
|
||||
long timestamp = System.currentTimeMillis() / 1000;
|
||||
params.put("timestamp", Long.toString(timestamp));
|
||||
params.put("sign",sign(params,agisoConfig.getAppsecret()));
|
||||
|
||||
//构建公共请求头
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", "Bearer " + accessToken);
|
||||
headers.put("ApiVersion", "1");
|
||||
//执行请求
|
||||
return HttpUtils.execute(url,method, headers, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgisoResponse doPost(String url, Map<String, String> params, String sellerOpenUid) throws NoSuchAlgorithmException {
|
||||
return execute(url,"POST",params,sellerOpenUid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgisoResponse doGet(String url, Map<String, String> params, String sellerOpenUid) throws NoSuchAlgorithmException {
|
||||
return execute(url,"GET",params,sellerOpenUid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgisoResponse autoShipment(List<String> tids, String sellerOpenUid) throws NoSuchAlgorithmException {
|
||||
// 校验参数
|
||||
|
||||
if (tids == null || tids.isEmpty()) {
|
||||
log.warn("自动发货失败,订单ID列表为空");
|
||||
AgisoResponse emptyResponse = new AgisoResponse();
|
||||
emptyResponse.setSuccess(false);
|
||||
emptyResponse.setErrorCode(BAD_REQUEST);
|
||||
emptyResponse.setErrorMsg("订单ID列表不能为空");
|
||||
return emptyResponse;
|
||||
}
|
||||
|
||||
// 拼接订单ID字符串(去除最后一个逗号)
|
||||
String tidsStr = String.join(",", tids);
|
||||
log.debug("自动发货处理,订单ID列表:{},商家标识:{}", tidsStr, sellerOpenUid);
|
||||
|
||||
// 构建请求参数
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("tids", tidsStr);
|
||||
|
||||
// 调用POST请求方法
|
||||
return doPost(AUTO_SHIPMENTS_URL, params, sellerOpenUid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 阿奇索签名算法
|
||||
* @param params 业务参数
|
||||
* @param appSecret appsecret
|
||||
* @return 签名字符串
|
||||
* @throws NoSuchAlgorithmException 未找到算法异常
|
||||
*/
|
||||
@Override
|
||||
public String sign(Map<String, String> params, String appSecret) throws NoSuchAlgorithmException {
|
||||
String[] keys = params.keySet().toArray(new String[0]);
|
||||
Arrays.sort(keys);
|
||||
|
||||
StringBuilder query = new StringBuilder();
|
||||
query.append(appSecret);
|
||||
for (String key : keys) {
|
||||
String value = params.get(key);
|
||||
query.append(key).append(value);
|
||||
}
|
||||
query.append(appSecret);
|
||||
|
||||
byte[] md5byte = encryptMD5(query.toString());
|
||||
|
||||
return byte2hex(md5byte);
|
||||
}
|
||||
|
||||
// byte数组转成16进制字符串
|
||||
private String byte2hex(byte[] bytes) {
|
||||
StringBuilder sign = new StringBuilder();
|
||||
for (byte aByte : bytes) {
|
||||
String hex = Integer.toHexString(aByte & 0xFF);
|
||||
if (hex.length() == 1) {
|
||||
sign.append("0");
|
||||
}
|
||||
sign.append(hex.toLowerCase());
|
||||
}
|
||||
return sign.toString();
|
||||
}
|
||||
|
||||
// Md5摘要
|
||||
private byte[] encryptMD5(String data) throws NoSuchAlgorithmException {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
return md5.digest(data.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
@@ -0,0 +1,131 @@
|
||||
package cn.iocoder.yudao.module.kfc.utils;
|
||||
|
||||
import cn.iocoder.yudao.module.kfc.controller.admin.agisoproxy.vo.AgisoData;
|
||||
import cn.iocoder.yudao.module.kfc.controller.admin.agisoproxy.vo.AgisoResponse;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
public class HttpUtils {
|
||||
// 单例OkHttpClient实例
|
||||
private static final OkHttpClient client = new OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.build();
|
||||
|
||||
// 用于JSON反序列化的ObjectMapper
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
/**
|
||||
* 通用HTTP请求执行方法,返回结构化的AgisoResponse
|
||||
* @param url 请求URL
|
||||
* @param method 请求方法(GET, POST, PUT, DELETE等)
|
||||
* @param headers 请求头
|
||||
* @param params 请求参数
|
||||
* @return 结构化的AgisoResponse响应
|
||||
*/
|
||||
public static AgisoResponse execute(String url, String method, Map<String, String> headers, Map<String, String> params) {
|
||||
// 参数处理
|
||||
if (params == null) {
|
||||
params = new HashMap<>();
|
||||
}
|
||||
if (headers == null) {
|
||||
headers = new HashMap<>();
|
||||
}
|
||||
|
||||
// 构建请求体
|
||||
RequestBody requestBody = null;
|
||||
if ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method)) {
|
||||
FormBody.Builder formBuilder = new FormBody.Builder();
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
formBuilder.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
requestBody = formBuilder.build();
|
||||
}
|
||||
// GET请求参数拼接
|
||||
else if ("GET".equalsIgnoreCase(method) && !params.isEmpty()) {
|
||||
url = url + (url.contains("?") ? "&" : "?") + buildQueryString(params);
|
||||
}
|
||||
|
||||
// 构建请求
|
||||
Request.Builder requestBuilder = new Request.Builder()
|
||||
.url(url);
|
||||
|
||||
// 添加请求头
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
requestBuilder.addHeader(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// 设置请求方法
|
||||
Request request;
|
||||
if ("GET".equalsIgnoreCase(method)) {
|
||||
request = requestBuilder.get().build();
|
||||
} else if ("DELETE".equalsIgnoreCase(method)) {
|
||||
request = requestBuilder.delete().build();
|
||||
} else {
|
||||
request = requestBuilder.method(method, requestBody).build();
|
||||
}
|
||||
|
||||
// 执行请求并处理响应
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
String responseBody = response.body() != null ? response.body().string() : "";
|
||||
log.debug("HTTP请求响应内容: {}", responseBody);
|
||||
|
||||
// 尝试将响应体反序列化为AgisoResponse
|
||||
if (!responseBody.isEmpty()) {
|
||||
return objectMapper.readValue(responseBody, AgisoResponse.class);
|
||||
}
|
||||
|
||||
// 响应体为空时构建默认失败响应
|
||||
AgisoResponse emptyResponse = new AgisoResponse();
|
||||
emptyResponse.setSuccess(false);
|
||||
emptyResponse.setErrorCode(response.code());
|
||||
emptyResponse.setErrorMsg("响应体为空");
|
||||
return emptyResponse;
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("请求执行异常:{}", e.getMessage(), e);
|
||||
// 异常时构建失败响应
|
||||
AgisoResponse errorResponse = new AgisoResponse();
|
||||
errorResponse.setSuccess(false);
|
||||
errorResponse.setErrorCode(500);
|
||||
errorResponse.setErrorMsg("请求异常:" + e.getMessage());
|
||||
return errorResponse;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化的POST请求方法,返回结构化响应
|
||||
*/
|
||||
public static AgisoResponse post(String url, Map<String, String> headers, Map<String, String> params) {
|
||||
return execute(url, "POST", headers, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 简化的GET请求方法,返回结构化响应
|
||||
*/
|
||||
public static AgisoResponse get(String url, Map<String, String> headers, Map<String, String> params) {
|
||||
return execute(url, "GET", headers, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询字符串
|
||||
*/
|
||||
private static String buildQueryString(Map<String, String> params) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("&");
|
||||
}
|
||||
sb.append(entry.getKey()).append("=").append(entry.getValue());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@@ -272,6 +272,7 @@ pf4j:
|
||||
# pluginsDir: /tmp/
|
||||
pluginsDir: ../plugins
|
||||
|
||||
# 阿奇索的配置
|
||||
agiso:
|
||||
appid: appid
|
||||
appsecret: appsecret
|
Reference in New Issue
Block a user