|
|
|
@ -1,14 +1,22 @@
|
|
|
|
|
package com.dsideal.aiSupport.Util.JiMeng.Kit;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.http.Method;
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import com.dsideal.aiSupport.Plugin.YamlProp;
|
|
|
|
|
import com.google.common.io.ByteStreams;
|
|
|
|
|
import com.jfinal.kit.Prop;
|
|
|
|
|
import org.apache.commons.codec.binary.Hex;
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
import cn.hutool.core.io.FileUtil;
|
|
|
|
|
import cn.hutool.http.HttpRequest;
|
|
|
|
|
import cn.hutool.http.HttpResponse;
|
|
|
|
|
import cn.hutool.http.HttpUtil;
|
|
|
|
|
|
|
|
|
|
import javax.crypto.Mac;
|
|
|
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.OutputStream;
|
|
|
|
|
import java.net.HttpURLConnection;
|
|
|
|
@ -27,6 +35,8 @@ import static com.dsideal.aiSupport.AiSupportApplication.getEnvPrefix;
|
|
|
|
|
* 用于处理火山引擎API的请求签名和发送
|
|
|
|
|
*/
|
|
|
|
|
public class JmCommon {
|
|
|
|
|
private static final Logger log = LoggerFactory.getLogger(JmCommon.class);
|
|
|
|
|
|
|
|
|
|
// 请求域名
|
|
|
|
|
public static String host = "visual.volcengineapi.com";
|
|
|
|
|
public static String path = "/"; // 路径,不包含 Query
|
|
|
|
@ -35,20 +45,21 @@ public class JmCommon {
|
|
|
|
|
public static String region = "cn-north-1"; // 区域,固定为cn-north-1
|
|
|
|
|
public static String schema = "https"; // 协议,使用https
|
|
|
|
|
public static String version = "2022-08-31"; // API版本号
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// URL编码相关常量
|
|
|
|
|
private static final BitSet URLENCODER = new BitSet(256);
|
|
|
|
|
private static final String CONST_ENCODE = "0123456789ABCDEF";
|
|
|
|
|
public static final Charset UTF_8 = StandardCharsets.UTF_8;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// API访问凭证
|
|
|
|
|
protected static final String ak; // Access Key
|
|
|
|
|
protected static final String sk; // Secret Key
|
|
|
|
|
public static Prop PropKit; // 配置文件工具
|
|
|
|
|
// 获取项目根目录路径
|
|
|
|
|
protected static String projectRoot = System.getProperty("user.dir").replace("\\","/")+"/dsAiSupport";
|
|
|
|
|
protected static String projectRoot = System.getProperty("user.dir").replace("\\", "/") + "/dsAiSupport";
|
|
|
|
|
// 拼接相对路径
|
|
|
|
|
protected static String basePath = projectRoot + "/src/main/java/com/dsideal/aiSupport/Util/JiMeng/Example/";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 静态初始化块
|
|
|
|
|
* 加载配置文件并初始化URL编码器
|
|
|
|
@ -77,14 +88,13 @@ public class JmCommon {
|
|
|
|
|
URLENCODER.set('~');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 发送HTTP请求到火山引擎API
|
|
|
|
|
*
|
|
|
|
|
* @param method 请求方法,如GET、POST
|
|
|
|
|
* 使用Hutool发送HTTP请求到火山引擎API
|
|
|
|
|
*
|
|
|
|
|
* @param method 请求方法,如GET、POST
|
|
|
|
|
* @param queryList 查询参数列表
|
|
|
|
|
* @param body 请求体数据
|
|
|
|
|
* @param action API操作名称
|
|
|
|
|
* @param body 请求体数据
|
|
|
|
|
* @param action API操作名称
|
|
|
|
|
* @return 响应体字符串
|
|
|
|
|
* @throws Exception 请求过程中的异常
|
|
|
|
|
*/
|
|
|
|
@ -95,13 +105,13 @@ public class JmCommon {
|
|
|
|
|
}
|
|
|
|
|
// 计算请求体的SHA256哈希值
|
|
|
|
|
String xContentSha256 = hashSHA256(body);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化日期时间,用于请求头
|
|
|
|
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
|
|
|
|
|
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
|
|
|
String xDate = sdf.format(date);
|
|
|
|
|
String shortXDate = xDate.substring(0, 8); // 提取日期部分,用于凭证范围
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String contentType = "application/json"; // 内容类型
|
|
|
|
|
String signHeader = "host;x-date;x-content-sha256;content-type"; // 签名头部列表
|
|
|
|
|
|
|
|
|
@ -124,10 +134,10 @@ public class JmCommon {
|
|
|
|
|
"\n" +
|
|
|
|
|
signHeader + "\n" +
|
|
|
|
|
xContentSha256;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 计算规范请求字符串的哈希值
|
|
|
|
|
String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建凭证范围和签名字符串
|
|
|
|
|
String credentialScope = shortXDate + "/" + region + "/" + service + "/request";
|
|
|
|
|
String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;
|
|
|
|
@ -135,50 +145,70 @@ public class JmCommon {
|
|
|
|
|
// 生成签名密钥并计算签名
|
|
|
|
|
byte[] signKey = genSigningSecretKeyV4(shortXDate, region, service);
|
|
|
|
|
String signature = HexFormat.of().formatHex(hmacSHA256(signKey, signString));
|
|
|
|
|
|
|
|
|
|
// 构建URL并创建HTTP连接
|
|
|
|
|
URL url = new URL(schema + "://" + host + path + "?" + querySB);
|
|
|
|
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
|
|
|
|
conn.setRequestMethod(method);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建URL
|
|
|
|
|
String url = schema + "://" + host + path + "?" + querySB;
|
|
|
|
|
|
|
|
|
|
// 使用Hutool发送HTTP请求
|
|
|
|
|
HttpRequest request = HttpRequest.of(url);
|
|
|
|
|
// 将字符串方法名转换为Method枚举
|
|
|
|
|
Method httpMethod = Method.valueOf(method.toUpperCase());
|
|
|
|
|
request.method(httpMethod);
|
|
|
|
|
|
|
|
|
|
// 设置请求头
|
|
|
|
|
conn.setRequestProperty("Host", host);
|
|
|
|
|
conn.setRequestProperty("X-Date", xDate);
|
|
|
|
|
conn.setRequestProperty("X-Content-Sha256", xContentSha256);
|
|
|
|
|
conn.setRequestProperty("Content-Type", contentType);
|
|
|
|
|
conn.setRequestProperty("Authorization", "HMAC-SHA256" +
|
|
|
|
|
request.header("Host", host);
|
|
|
|
|
request.header("X-Date", xDate);
|
|
|
|
|
request.header("X-Content-Sha256", xContentSha256);
|
|
|
|
|
request.header("Content-Type", contentType);
|
|
|
|
|
request.header("Authorization", "HMAC-SHA256" +
|
|
|
|
|
" Credential=" + ak + "/" + credentialScope +
|
|
|
|
|
", SignedHeaders=" + signHeader +
|
|
|
|
|
", Signature=" + signature);
|
|
|
|
|
|
|
|
|
|
// 如果不是GET请求,写入请求体
|
|
|
|
|
if (!Objects.equals(conn.getRequestMethod(), "GET")) {
|
|
|
|
|
conn.setDoOutput(true);
|
|
|
|
|
OutputStream os = conn.getOutputStream();
|
|
|
|
|
os.write(body);
|
|
|
|
|
os.flush();
|
|
|
|
|
os.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 建立连接并获取响应
|
|
|
|
|
conn.connect();
|
|
|
|
|
int responseCode = conn.getResponseCode();
|
|
|
|
|
InputStream is;
|
|
|
|
|
if (responseCode == 200) {
|
|
|
|
|
is = conn.getInputStream(); // 成功响应
|
|
|
|
|
} else {
|
|
|
|
|
is = conn.getErrorStream(); // 错误响应
|
|
|
|
|
|
|
|
|
|
// 如果不是GET请求,设置请求体
|
|
|
|
|
if (!method.equals("GET") && body.length > 0) {
|
|
|
|
|
request.body(body);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取响应内容并关闭流
|
|
|
|
|
String responseBody = new String(ByteStreams.toByteArray(is));
|
|
|
|
|
is.close();
|
|
|
|
|
|
|
|
|
|
// 发送请求并获取响应
|
|
|
|
|
HttpResponse response = request.execute();
|
|
|
|
|
String responseBody = response.body();
|
|
|
|
|
|
|
|
|
|
// 关闭响应
|
|
|
|
|
response.close();
|
|
|
|
|
|
|
|
|
|
return responseBody;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 从URL下载文件到指定路径
|
|
|
|
|
*
|
|
|
|
|
* @param fileUrl 文件URL
|
|
|
|
|
* @param saveFilePath 保存路径
|
|
|
|
|
* @throws Exception 下载过程中的异常
|
|
|
|
|
*/
|
|
|
|
|
public static void downloadFile(String fileUrl, String saveFilePath) throws Exception {
|
|
|
|
|
try {
|
|
|
|
|
// 确保目录存在
|
|
|
|
|
File file = new File(saveFilePath);
|
|
|
|
|
File parentDir = file.getParentFile();
|
|
|
|
|
if (parentDir != null && !parentDir.exists()) {
|
|
|
|
|
parentDir.mkdirs();
|
|
|
|
|
log.info("创建目录: {}", parentDir.getAbsolutePath());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 使用Hutool下载文件
|
|
|
|
|
long fileSize = HttpUtil.downloadFile(fileUrl, FileUtil.file(saveFilePath));
|
|
|
|
|
log.info("文件下载成功,保存路径: {}, 文件大小: {}字节", saveFilePath, fileSize);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
log.error("文件下载失败: {}", e.getMessage(), e);
|
|
|
|
|
throw new Exception("文件下载失败: " + e.getMessage(), e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* URL编码字符串,用于签名
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param source 源字符串
|
|
|
|
|
* @return 编码后的字符串
|
|
|
|
|
*/
|
|
|
|
@ -211,7 +241,7 @@ public class JmCommon {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 计算内容的SHA256哈希值
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* @param content 要计算哈希的内容
|
|
|
|
|
* @return 十六进制表示的哈希值
|
|
|
|
|
* @throws Exception 计算过程中的异常
|
|
|
|
@ -227,8 +257,8 @@ public class JmCommon {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 使用HMAC-SHA256算法计算消息认证码
|
|
|
|
|
*
|
|
|
|
|
* @param key 密钥
|
|
|
|
|
*
|
|
|
|
|
* @param key 密钥
|
|
|
|
|
* @param content 内容
|
|
|
|
|
* @return 计算结果
|
|
|
|
|
* @throws Exception 计算过程中的异常
|
|
|
|
@ -246,9 +276,9 @@ public class JmCommon {
|
|
|
|
|
/**
|
|
|
|
|
* 生成V4版本的签名密钥
|
|
|
|
|
* 使用AWS签名V4算法的派生密钥过程
|
|
|
|
|
*
|
|
|
|
|
* @param date 日期字符串
|
|
|
|
|
* @param region 区域
|
|
|
|
|
*
|
|
|
|
|
* @param date 日期字符串
|
|
|
|
|
* @param region 区域
|
|
|
|
|
* @param service 服务名称
|
|
|
|
|
* @return 派生的签名密钥
|
|
|
|
|
* @throws Exception 生成过程中的异常
|
|
|
|
|