ZaloPay.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. package com.ruoyi.app.utils.zaloPay;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.ruoyi.app.utils.zaloPayCrypto.HMACUtil;
  5. import org.apache.http.NameValuePair;
  6. import org.apache.http.client.entity.UrlEncodedFormEntity;
  7. import org.apache.http.client.methods.CloseableHttpResponse;
  8. import org.apache.http.client.methods.HttpPost;
  9. import org.apache.http.client.utils.URIBuilder;
  10. import org.apache.http.impl.client.CloseableHttpClient;
  11. import org.apache.http.impl.client.HttpClients;
  12. import org.apache.http.message.BasicNameValuePair;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.stereotype.Component;
  15. import java.io.BufferedReader;
  16. import java.io.IOException;
  17. import java.io.InputStreamReader;
  18. import java.io.UnsupportedEncodingException;
  19. import java.net.URISyntaxException;
  20. import java.text.SimpleDateFormat;
  21. import java.util.*;
  22. /**
  23. * ZaloPay 工具类
  24. *
  25. * @author ruoyi
  26. **/
  27. @Component
  28. public class ZaloPay {
  29. @Autowired
  30. private ZaloPayApiProperties apiProperties;
  31. /**
  32. * 生成 HMAC SHA256 签名
  33. */
  34. public static String getCurrentTimeString(String format) {
  35. Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT+7"));
  36. SimpleDateFormat fmt = new SimpleDateFormat(format);
  37. fmt.setCalendar(cal);
  38. return fmt.format(cal.getTimeInMillis());
  39. }
  40. /**
  41. * 创建ZaloPay订单,返回支付链接
  42. *
  43. * @param userId 用户唯一标识
  44. * @param orderId 订单号(建议格式:yymmdd_唯一编号)
  45. * @param amount 金额(单位:VND)
  46. * @param description 订单描述
  47. * @return ZaloPayCreateOrderResponse 支付响应数据
  48. */
  49. public ZaloPayCreateOrderResponse createOrder(String userId, String orderId, long amount, String description,ZaloPayProperties.ZaloPayConfig config) throws Exception {
  50. // ZaloPayConfig config = ZaloPayConfig.getZaloPayConfig(payType);
  51. String APP_ID = config.getApp_id();
  52. String KEY1 = config.getKey1();
  53. System.out.println("进入zalopay CreateOrder orderId: " + orderId+" amount: " + amount);
  54. // 从传入参数构建 embed_data
  55. final Map<String, Object> embed_data = new HashMap<>();
  56. // 如果有实际需要,可以在这里添加字段
  57. // 从传入参数构建 item 列表
  58. final List<Map<String, Object>> items = new ArrayList<>();
  59. // 示例:添加一个商品项
  60. Map<String, Object> item = new HashMap<>();
  61. // item.put("item_price", amount / 100); // 假设金额以分为单位
  62. // items.add(item);
  63. String appTransId =getCurrentTimeString("yyMMdd") + "_" + orderId;
  64. Map<String, Object> order = new HashMap<String, Object>(){{
  65. put("app_id", APP_ID);
  66. put("app_trans_id", appTransId);
  67. put("app_time", System.currentTimeMillis()); //毫米级时间戳,时间戳与时区无关 miliseconds
  68. put("app_user", userId);
  69. put("amount", amount);
  70. put("description", description);
  71. //钱包支付
  72. if(config.getPay_type().equals("3")){
  73. put("bank_code", "zalopayapp");
  74. put("embed_data", "{}");
  75. }
  76. //银行卡支付
  77. if(config.getPay_type().equals("5")){
  78. put("bank_code", "");
  79. put("embed_data", "{\"preferred payment method\":[\"domestic card\",\"account\"],\"redirecturl\":\"cityexpressuser://\"}");
  80. }
  81. if(config.getPay_type().equals("4")){
  82. put("bank_code", "");
  83. put("embed_data", "{\"preferred payment method\":[\"vietqr\"],\"redirecturl\":\"cityexpressuser://\"}");
  84. }
  85. put("item", "[]");
  86. }};
  87. String data = order.get("app_id") +"|"+ order.get("app_trans_id") +"|"+ order.get("app_user") +"|"+ order.get("amount")
  88. +"|"+ order.get("app_time") +"|"+ order.get("embed_data") +"|"+ order.get("item");
  89. order.put("mac", HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, KEY1, data));
  90. System.out.println("ZaloPay CreateOrder 创建的 order信息: " + order);
  91. HttpPost post=createPost(order, apiProperties.getCreate_order_url());
  92. // 添加日志和异常处理
  93. try (CloseableHttpClient httpClient = HttpClients.createDefault();
  94. CloseableHttpResponse res = httpClient.execute(post)) {
  95. BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent()));
  96. StringBuilder resultJsonStr = new StringBuilder();
  97. String line;
  98. while ((line = rd.readLine()) != null) {
  99. resultJsonStr.append(line);
  100. }
  101. String responseJson = resultJsonStr.toString();
  102. System.out.println("ZaloPay CreateOrder Response: " + responseJson); // 日志输出
  103. return JSON.parseObject(responseJson, ZaloPayCreateOrderResponse.class);
  104. }
  105. }
  106. /**
  107. * 查询订单支付状态
  108. *
  109. * @param appTransId 订单号
  110. * @return 支付状态
  111. */
  112. public ZaloPayQueryOrderResponse queryOrderStatus(String appTransId,ZaloPayProperties.ZaloPayConfig config) throws URISyntaxException, IOException {
  113. String APP_ID = config.getApp_id();
  114. String KEY1 = config.getKey1();
  115. String data = APP_ID +"|"+ appTransId +"|"+ KEY1; // appid|app_trans_id|key1
  116. String mac = HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, KEY1, data);
  117. List<NameValuePair> params = new ArrayList<>();
  118. params.add(new BasicNameValuePair("app_id", APP_ID));
  119. params.add(new BasicNameValuePair("app_trans_id", appTransId));
  120. params.add(new BasicNameValuePair("mac", mac));
  121. URIBuilder uri = new URIBuilder(apiProperties.getQuery_order_url());
  122. uri.addParameters(params);
  123. CloseableHttpClient client = HttpClients.createDefault();
  124. HttpPost post = new HttpPost(uri.build());
  125. post.setEntity(new UrlEncodedFormEntity(params));
  126. CloseableHttpResponse res = client.execute(post);
  127. BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent()));
  128. StringBuilder resultJsonStr = new StringBuilder();
  129. String line;
  130. while ((line = rd.readLine()) != null) {
  131. resultJsonStr.append(line);
  132. }
  133. JSONObject result = JSON.parseObject(resultJsonStr.toString());
  134. for (String key : result.keySet()) {
  135. System.out.format("%s = %s\n", key, result.get(key));
  136. }
  137. System.out.println("ZaloPay QueryOrder Response: " + resultJsonStr);
  138. return JSON.parseObject(resultJsonStr.toString(), ZaloPayQueryOrderResponse.class);
  139. }
  140. /**
  141. * 退款
  142. *
  143. * @param zpTransId
  144. * @param amount
  145. * @return ZaloPayRefundResponse 退款响应数据
  146. */
  147. public ZaloPayRefundResponse Refund(String zpTransId, long amount,String mRefundId,ZaloPayProperties.ZaloPayConfig config) throws Exception {
  148. String APP_ID = config.getApp_id();
  149. String KEY1 = config.getKey1();
  150. String appid = APP_ID;
  151. long timestamp = System.currentTimeMillis(); // miliseconds
  152. Map<String, Object> order = new HashMap<String, Object>() {{
  153. put("app_id", appid);
  154. put("zp_trans_id", zpTransId); // 使用传入的 zpTransId
  155. // put("m_refund_id", getCurrentTimeString("yyMMdd") + "_" + appid + "_" + ddId);
  156. put("m_refund_id", mRefundId);
  157. put("timestamp", timestamp);
  158. put("amount", amount); // 使用传入的 amount
  159. put("description", "ZaloPay Intergration Demo");
  160. }};
  161. // appid|zptransid|amount|description|timestamp
  162. String data = order.get("app_id") + "|" + order.get("zp_trans_id") + "|" + order.get("amount")
  163. + "|" + order.get("description") + "|" + order.get("timestamp");
  164. order.put("mac", HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, KEY1, data));
  165. CloseableHttpClient client = HttpClients.createDefault();
  166. HttpPost post = createPost(order, apiProperties.getRefund_url());
  167. CloseableHttpResponse res = client.execute(post);
  168. BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent()));
  169. StringBuilder resultJsonStr = new StringBuilder();
  170. String line;
  171. while ((line = rd.readLine()) != null) {
  172. resultJsonStr.append(line);
  173. }
  174. System.out.println("ZaloPay Refund Response: " + resultJsonStr.toString()); // 日志输出
  175. // 解析响应数据为 ZaloPayRefundResponse 对象
  176. return JSON.parseObject(resultJsonStr.toString(), ZaloPayRefundResponse.class);
  177. }
  178. /**
  179. * 查询退款状态
  180. *
  181. * @param m_refund_id 退款单号
  182. * @return 退款状态
  183. */
  184. public ZaloPayQueryRefundResponse queryRefundStatus(String m_refund_id, ZaloPayProperties.ZaloPayConfig config) throws URISyntaxException, IOException {
  185. String APP_ID = config.getApp_id();
  186. String KEY1 = config.getKey1();
  187. String timestamp = Long.toString(System.currentTimeMillis()); // miliseconds
  188. String data = APP_ID +"|"+ m_refund_id +"|"+ timestamp; // app_id|m_refund_id|timestamp
  189. String mac = HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, KEY1, data);
  190. List<NameValuePair> params = new ArrayList<>();
  191. params.add(new BasicNameValuePair("app_id", APP_ID));
  192. params.add(new BasicNameValuePair("m_refund_id", m_refund_id));
  193. params.add(new BasicNameValuePair("timestamp", timestamp));
  194. params.add(new BasicNameValuePair("mac", mac));
  195. URIBuilder uri = new URIBuilder(apiProperties.getQuery_refund_url());
  196. uri.addParameters(params);
  197. CloseableHttpClient client = HttpClients.createDefault();
  198. HttpPost post = new HttpPost(uri.build());
  199. post.setEntity(new UrlEncodedFormEntity(params));
  200. CloseableHttpResponse res = client.execute(post);
  201. BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent()));
  202. StringBuilder resultJsonStr = new StringBuilder();
  203. String line;
  204. while ((line = rd.readLine()) != null) {
  205. resultJsonStr.append(line);
  206. }
  207. System.out.println("ZaloPay QueryRefund Response: " + resultJsonStr);
  208. return JSON.parseObject(resultJsonStr.toString(), ZaloPayQueryRefundResponse.class);
  209. }
  210. public static HttpPost createPost(Map<String, Object> order, String refundUrl) throws UnsupportedEncodingException {
  211. HttpPost post = new HttpPost(refundUrl);
  212. List<NameValuePair> params = new ArrayList<>();
  213. for (Map.Entry<String, Object> e : order.entrySet()) {
  214. params.add(new BasicNameValuePair(e.getKey(), e.getValue().toString()));
  215. }
  216. post.setEntity(new UrlEncodedFormEntity(params));
  217. return post;
  218. }
  219. }