test.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. import com.alibaba.fastjson.JSON;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.malk.rjk.Boot;
  5. import com.malk.rjk.server.RjkServer;
  6. import com.malk.server.common.McException;
  7. import com.smecloud.apigw.client.ApigwClient;
  8. import com.smecloud.apigw.model.ApiRequest;
  9. import com.smecloud.apigw.model.ApiResult;
  10. import com.smecloud.apigw.model.ApigwConfig;
  11. import lombok.extern.slf4j.Slf4j;
  12. import org.apache.http.HttpResponse;
  13. import org.apache.http.client.methods.HttpGet;
  14. import org.apache.http.client.methods.HttpPost;
  15. import org.apache.http.entity.StringEntity;
  16. import org.apache.http.impl.client.CloseableHttpClient;
  17. import org.apache.http.impl.client.HttpClients;
  18. import org.apache.http.util.EntityUtils;
  19. import org.junit.Test;
  20. import org.junit.runner.RunWith;
  21. import org.springframework.beans.factory.annotation.Autowired;
  22. import org.springframework.boot.test.context.SpringBootTest;
  23. import org.springframework.test.context.junit4.SpringRunner;
  24. import javax.crypto.Mac;
  25. import javax.crypto.spec.SecretKeySpec;
  26. import java.io.IOException;
  27. import java.io.UnsupportedEncodingException;
  28. import java.net.*;
  29. import java.nio.charset.StandardCharsets;
  30. import java.security.InvalidKeyException;
  31. import java.security.NoSuchAlgorithmException;
  32. import java.util.*;
  33. import static com.smecloud.apigw.constant.HttpMethod.GET;
  34. @Slf4j
  35. @RunWith(SpringRunner.class)
  36. @SpringBootTest(classes = Boot.class)
  37. public class test {
  38. @Test
  39. public void testService() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
  40. Map<String, String> mes_params = push_app_authorize("300657", "9163551ef2e2a2cd2398dc05ec527132", "356919829745242112");//根据应用ID(Client ID),第三方实例ID调取实时
  41. if (mes_params.size() > 0) {
  42. String appSecret = mes_params.get("appSecret").toString();
  43. String domain = mes_params.get("domain").toString();
  44. if (domain != "" && appSecret != "" && domain != null && appSecret != null) {
  45. get_material("300657", domain, appSecret, "9163551ef2e2a2cd2398dc05ec527132");
  46. }
  47. }
  48. //
  49. // CookieStore cookieStore = new BasicCookieStore();
  50. // // 创建一个 Httpclient 实例
  51. // CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
  52. // HttpGet otherRequest = new HttpGet("https://api.kingdee.com/jdy/v2/bd/material");
  53. // otherRequest.setHeader("Content-Type", "300657");
  54. // otherRequest.setHeader("X-Api-ClientID", "application/json");
  55. // otherRequest.setHeader("X-Api-Auth-Version", "2.0");
  56. // otherRequest.setHeader("X-Api-TimeStamp", String.valueOf(System.currentTimeMillis()));
  57. // otherRequest.setHeader("X-Api-SignHeaders", "X-Api-TimeStamp,X-Api-Nonce");
  58. // otherRequest.setHeader("X-Api-Nonce", this.get_randomNumber());
  59. // otherRequest.setHeader("X-Api-Signature", get_app_signature("tcyhmh71","206bfff1ea61c4699f55ce895848c3e52a8dff02"));
  60. // otherRequest.setHeader("app-token", this.get_appToken());
  61. // otherRequest.setHeader("X-GW-Router-Addr", this.get_appToken());
  62. // CloseableHttpResponse otherResponse = httpclient.execute(otherRequest);
  63. }
  64. /**
  65. * 主动获取授权
  66. *
  67. * @return
  68. */
  69. public static Map<String, String> push_app_authorize(String clientId, String Secret, String outerInstanceId) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
  70. Map<String, String> mes_params = new TreeMap<>();
  71. String url = "https://api.kingdee.com/jdyconnector/app_management/push_app_authorize?outerInstanceId=" + outerInstanceId;
  72. HttpPost httpPost = new HttpPost(url);
  73. String TimeStamp = String.valueOf(System.currentTimeMillis());
  74. String randomNumber = get_randomNumber();
  75. /**
  76. * Signature加密
  77. */
  78. String QQFS = "POST";
  79. String path = "/jdyconnector/app_management/push_app_authorize";
  80. Map<String, String> params = new TreeMap<>(); // TreeMap 会自动按键的 ASCII 码排序
  81. params.put("outerInstanceId", outerInstanceId);
  82. String Signature = get_app_signature(Secret, QQFS, path, params, TimeStamp, randomNumber);//X-Api-Signature加密获取
  83. httpPost.setHeader("X-Api-ClientID", clientId);
  84. httpPost.setHeader("X-Api-Auth-Version", "2.0");
  85. httpPost.setHeader("X-Api-TimeStamp", TimeStamp);
  86. httpPost.setHeader("X-Api-Nonce", randomNumber);
  87. httpPost.setHeader("X-Api-SignHeaders", "X-Api-TimeStamp,X-Api-Nonce");
  88. httpPost.setHeader("X-Api-Signature", Signature);
  89. // 设置请求体(如果有)
  90. httpPost.setEntity(new StringEntity("", "UTF-8"));
  91. try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
  92. // 发送请求并处理响应
  93. HttpResponse response = httpClient.execute(httpPost);
  94. String responseBody = EntityUtils.toString(response.getEntity());
  95. JSONObject jsonObject = JSON.parseObject(responseBody);
  96. if (jsonObject.getString("code").equals("200")) {
  97. JSONArray dataArray = jsonObject.getJSONArray("data");
  98. // 假设JSON数组中只有一个对象,或者我们只关心第一个对象
  99. JSONObject dataObject = dataArray.getJSONObject(0);
  100. String appSecret = dataObject.getString("appSecret");
  101. String domain = dataObject.getString("domain");
  102. mes_params.put("appSecret", appSecret);
  103. mes_params.put("domain", domain);
  104. } else {
  105. }
  106. } catch (Exception e) {
  107. e.printStackTrace();
  108. }
  109. return mes_params;
  110. }
  111. /**
  112. * 获取商品列表
  113. *
  114. * @return
  115. */
  116. public static String get_material(String clientId, String domain, String appSecret, String Secret) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
  117. String url = "https://api.kingdee.com/jdy/v2/bd/material";
  118. HttpGet httpGet = new HttpGet(url);
  119. String TimeStamp = String.valueOf(System.currentTimeMillis());
  120. String randomNumber = get_randomNumber();
  121. /**
  122. * Signature加密
  123. */
  124. String QQFS = "GET";
  125. String path = "/jdy/v2/bd/material";
  126. Map<String, String> params = new TreeMap<>(); // TreeMap 会自动按键的 ASCII 码排序
  127. String Signature = get_app_signature(Secret, QQFS, path, params, TimeStamp, randomNumber);//X-Api-Signature加密获取
  128. httpGet.setHeader("X-Api-ClientID", clientId);
  129. httpGet.setHeader("X-Api-Auth-Version", "2.0");
  130. httpGet.setHeader("X-Api-TimeStamp", TimeStamp);
  131. httpGet.setHeader("X-Api-Nonce", randomNumber);
  132. httpGet.setHeader("X-Api-SignHeaders", "X-Api-TimeStamp,X-Api-Nonce");
  133. httpGet.setHeader("X-Api-Signature", Signature);
  134. httpGet.setHeader("Content-Type", "application/json");
  135. httpGet.setHeader("app-token", get_appToken(appSecret));
  136. httpGet.setHeader("X-GW-Router-Addr", domain);
  137. try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
  138. // 发送请求并处理响应
  139. HttpResponse response = httpClient.execute(httpGet);
  140. String responseBody = EntityUtils.toString(response.getEntity());
  141. JSONObject jsonObject = JSON.parseObject(responseBody);
  142. System.out.println("jsonObject:" + jsonObject);
  143. String errcode = jsonObject.getString("errcode");
  144. if (errcode.equals("0")) {//判断有返回值
  145. JSONObject dataObject = jsonObject.getJSONObject("data");
  146. // 从data对象中获取rows数组
  147. JSONArray rowsArray = dataObject.getJSONArray("rows");
  148. // 循环遍历rows数组中的每个对象
  149. for (int i = 0; i < rowsArray.size(); i++) {
  150. JSONObject rowObject = rowsArray.getJSONObject(i);
  151. // 获取rowObject中的任意字段,例如name
  152. String shop_name = rowObject.getString("name");//商品名称
  153. String shop_number = rowObject.getString("number");//商品编码
  154. if (!shop_number.equals("")){
  155. }
  156. // 打印或其他处理
  157. System.out.println("商品名称: " + shop_name);
  158. //根据编号查询详情
  159. // 你可以继续获取其他字段并进行处理
  160. }
  161. } else {
  162. }
  163. } catch (McException e) {
  164. System.out.println("e:"+e.getMessage());
  165. }
  166. return "";
  167. }
  168. //正整数
  169. public static String get_randomNumber() {
  170. Random random = new Random();
  171. // 指定随机数的范围(例如,1到100之间的随机正整数)
  172. int min = 100000000;
  173. int max = 999999999;
  174. // 生成随机数
  175. int randomNumber = random.nextInt((max - min) + 1) + min;
  176. return String.valueOf(randomNumber);
  177. }
  178. public static String get_appToken(String appSecret) throws IOException {
  179. ApigwConfig config = new ApigwConfig();
  180. //设置client_id
  181. config.setClientID("300657");
  182. //设置client_secret
  183. config.setClientSecret("9163551ef2e2a2cd2398dc05ec527132");
  184. ApigwClient apigwClient = ApigwClient.getInstance();
  185. //初始化API网关客户端
  186. apigwClient.init(config);
  187. ApiRequest request = new ApiRequest(GET, "api.kingdee.com", "/jdyconnector/app_management/kingdee_auth_token");
  188. Map<String, String> map = new HashMap<>();
  189. map.put("app_key", "tcyhmh71");
  190. String app_signature = get_app_signature("tcyhmh71", appSecret);
  191. map.put("app_signature", app_signature);
  192. request.setQuerys(map);
  193. request.setBodyJson(JSONObject.toJSONString("").getBytes());
  194. ApiResult result = ApigwClient.getInstance().send(request);
  195. // 解析JSON字符串
  196. String jsonBody = result.getBody();
  197. // 解析JSON字符串
  198. JSONObject jsonObject = JSON.parseObject(jsonBody);
  199. JSONObject dataObject = jsonObject.getJSONObject("data");
  200. // 获取app-token,注意fastjson对key中包含特殊字符(如-)的处理是自动的
  201. String appToken = dataObject.getString("app-token");
  202. System.out.println(appToken);
  203. return appToken;
  204. }
  205. //加密X-Api-Signature加密规则
  206. public static String get_app_signature(String app_key, String appSecret) {
  207. try {
  208. // 创建一个Mac实例,并指定使用HmacSHA256算法
  209. Mac mac = Mac.getInstance("HmacSHA256");
  210. // 使用appSecret作为密钥
  211. SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
  212. mac.init(secretKeySpec);
  213. // 对appKey进行加密
  214. byte[] hmacBytes = mac.doFinal(app_key.getBytes(StandardCharsets.UTF_8));
  215. // 将加密结果转换为16进制字符串
  216. StringBuilder hexString = new StringBuilder(2 * hmacBytes.length);
  217. for (byte b : hmacBytes) {
  218. String hex = Integer.toHexString(0xff & b);
  219. if (hex.length() == 1) hexString.append('0');
  220. hexString.append(hex);
  221. }
  222. // 将16进制字符串进行Base64编码
  223. byte[] hexBytes = hexString.toString().getBytes(StandardCharsets.UTF_8);
  224. String base64Encoded = Base64.getEncoder().encodeToString(hexBytes);
  225. return base64Encoded;
  226. } catch (NoSuchAlgorithmException | InvalidKeyException e) {
  227. throw new RuntimeException("Error while generating HMAC-SHA256 hash", e);
  228. }
  229. }
  230. //加密X-Api-Signature生成规则
  231. public static String get_app_signature(String clientSecret, String QQFS, String path, Map<String, String> params, String TimeStamp, String randomNumber) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
  232. String method = QQFS;
  233. String originalString = path;
  234. String target = "/"; // 要替换的字符,转换为字符串
  235. String replacement = "%2F"; // 替换后的字符串
  236. // 使用String的replace方法替换所有出现的target为replacement
  237. String encodedString = originalString.replace(target, replacement);
  238. StringBuilder signatureText = new StringBuilder();
  239. signatureText.append(method).append("\n");
  240. signatureText.append(encodedString).append("\n");
  241. // 拼接 params 参数(进行两次 URL 编码并转换为大写,但 TreeMap 已排序且只需编码一次)
  242. if (params != null) {
  243. Map<String, String> encodedParams = doubleUrlEncodeParams(params);
  244. // 按参数名的ASCII码升序排序
  245. List<Map.Entry<String, String>> sortedParams = new ArrayList<>(encodedParams.entrySet());
  246. sortedParams.sort(Comparator.comparing(Map.Entry::getKey));
  247. String signString = generateSignString(sortedParams);
  248. signatureText.append(signString).append("\n");
  249. System.out.println("签名字符串: " + signString);
  250. } else {
  251. signatureText.append("\n");
  252. }
  253. // 添加 headers 参数(x-api-nonce 和 x-api-timestamp,小写编码但拼接时保持原样)
  254. // 注意:这里实际上不需要再次编码,因为 nonce 和 timestamp 通常是数字或基64字符串,且规则要求小写(但编码后是大写字母的情况在这里不适用)
  255. signatureText.append("x-api-nonce:").append(randomNumber).append("\n");
  256. signatureText.append("x-api-timestamp:").append(TimeStamp).append("\n");
  257. // 输出签名原文(实际签名算法应在此原文基础上进行)
  258. System.out.println("Signature Text:\n" + signatureText.toString());
  259. String message = signatureText.toString();
  260. String hmacHex = get_app_signature(message, clientSecret);
  261. return hmacHex;
  262. }
  263. /**
  264. * 对参数值进行两次URL编码,并将字母转为大写
  265. */
  266. private static Map<String, String> doubleUrlEncodeParams(Map<String, String> params) {
  267. Map<String, String> encodedParams = new HashMap<>();
  268. for (Map.Entry<String, String> entry : params.entrySet()) {
  269. String key = entry.getKey();
  270. String value = entry.getValue();
  271. try {
  272. // 第一次URL编码
  273. String firstEncode = URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
  274. // 第二次URL编码
  275. String secondEncode = URLEncoder.encode(firstEncode, StandardCharsets.UTF_8.toString());
  276. // 转为大写
  277. encodedParams.put(key, secondEncode.toUpperCase());
  278. } catch (UnsupportedEncodingException e) {
  279. throw new RuntimeException("URL编码失败", e);
  280. }
  281. }
  282. return encodedParams;
  283. }
  284. /**
  285. * 生成签名字符串(key1=value1&key2=value2)
  286. */
  287. private static String generateSignString(List<Map.Entry<String, String>> sortedParams) {
  288. StringBuilder signString = new StringBuilder();
  289. for (Map.Entry<String, String> entry : sortedParams) {
  290. if (signString.length() > 0) {
  291. signString.append("&");
  292. }
  293. signString.append(entry.getKey()).append("=").append(entry.getValue());
  294. }
  295. return signString.toString();
  296. }
  297. public static String signMessage(String message, String clientSecret) throws NoSuchAlgorithmException, InvalidKeyException {
  298. // 创建一个HMAC-SHA256 Mac实例
  299. Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
  300. // 将clientSecret转换为密钥规范
  301. SecretKeySpec secretKeySpec = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
  302. // 初始化Mac实例
  303. sha256_HMAC.init(secretKeySpec);
  304. // 计算HMAC
  305. byte[] hmacBytes = sha256_HMAC.doFinal(message.getBytes(StandardCharsets.UTF_8));
  306. // 将字节数组转换为十六进制字符串
  307. return bytesToHex(hmacBytes);
  308. }
  309. /**
  310. * 将字节数组转换为十六进制字符串
  311. *
  312. * @param bytes 要转换的字节数组
  313. * @return 转换后的十六进制字符串
  314. */
  315. public static String bytesToHex(byte[] bytes) {
  316. Formatter formatter = new Formatter();
  317. for (byte b : bytes) {
  318. formatter.format("%02x", b);
  319. }
  320. String result = formatter.toString();
  321. formatter.close();
  322. return result;
  323. }
  324. @Autowired
  325. private RjkServer rjkServer;
  326. @Test
  327. public void testH3UserToweiling() {
  328. // 准备测试数据
  329. Map<String, String> testData = new HashMap<>();
  330. // 替换为实际的氚云业务对象ID
  331. // testData.put("BizObjectId", "0233a0df-24a1-4ee2-9de8-b4f3029b5594");
  332. // testData.put("BizObjectId", "d47b5b5b-0a4b-4120-8d08-6c5d79f8378f");
  333. // testData.put("BizObjectId", "151452f7-33f9-407e-a95e-5e040168ba3d");
  334. testData.put("BizObjectId", "967a68c1-5197-47cd-86e1-0a1cd42afb1f");
  335. // 调用H3UserToweiling方法
  336. rjkServer.H3UserToweiling(testData);
  337. }
  338. @Test
  339. public void testH3BusinessToWeiling() {
  340. // 准备测试数据
  341. Map<String, String> testData = new HashMap<>();
  342. // 替换为实际的氚云业务对象ID
  343. // testData.put("BizObjectId", "b7932c25-b081-498a-9c7e-da67c14208c2");
  344. testData.put("BizObjectId", "1f610bab-ada8-4247-a55c-d4d389450ce9");
  345. // 调用H3UserToweiling方法
  346. rjkServer.H3BusinessToWeiling(testData);
  347. }
  348. }