package com.ruoyi.app.utils.zaloPay; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.ruoyi.app.utils.zaloPayCrypto.HMACUtil; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.*; /** * ZaloPay 工具类 * * @author ruoyi **/ @Component public class ZaloPay { @Autowired private ZaloPayApiProperties apiProperties; /** * 生成 HMAC SHA256 签名 */ public static String getCurrentTimeString(String format) { Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT+7")); SimpleDateFormat fmt = new SimpleDateFormat(format); fmt.setCalendar(cal); return fmt.format(cal.getTimeInMillis()); } /** * 创建ZaloPay订单,返回支付链接 * * @param userId 用户唯一标识 * @param orderId 订单号(建议格式:yymmdd_唯一编号) * @param amount 金额(单位:VND) * @param description 订单描述 * @return ZaloPayCreateOrderResponse 支付响应数据 */ public ZaloPayCreateOrderResponse createOrder(String userId, String orderId, long amount, String description,ZaloPayProperties.ZaloPayConfig config) throws Exception { // ZaloPayConfig config = ZaloPayConfig.getZaloPayConfig(payType); String APP_ID = config.getApp_id(); String KEY1 = config.getKey1(); System.out.println("进入zalopay CreateOrder orderId: " + orderId+" amount: " + amount); // 从传入参数构建 embed_data final Map embed_data = new HashMap<>(); // 如果有实际需要,可以在这里添加字段 // 从传入参数构建 item 列表 final List> items = new ArrayList<>(); // 示例:添加一个商品项 Map item = new HashMap<>(); // item.put("item_price", amount / 100); // 假设金额以分为单位 // items.add(item); String appTransId =getCurrentTimeString("yyMMdd") + "_" + orderId; Map order = new HashMap(){{ put("app_id", APP_ID); put("app_trans_id", appTransId); put("app_time", System.currentTimeMillis()); //毫米级时间戳,时间戳与时区无关 miliseconds put("app_user", userId); put("amount", amount); put("description", description); //钱包支付 if(config.getPay_type().equals("3")){ put("bank_code", "zalopayapp"); put("embed_data", "{}"); } //银行卡支付 if(config.getPay_type().equals("5")){ put("bank_code", ""); put("embed_data", "{\"preferred payment method\":[\"domestic card\",\"account\"],\"redirecturl\":\"cityexpressuser://\"}"); } if(config.getPay_type().equals("4")){ put("bank_code", ""); put("embed_data", "{\"preferred payment method\":[\"vietqr\"],\"redirecturl\":\"cityexpressuser://\"}"); } put("item", "[]"); }}; String data = order.get("app_id") +"|"+ order.get("app_trans_id") +"|"+ order.get("app_user") +"|"+ order.get("amount") +"|"+ order.get("app_time") +"|"+ order.get("embed_data") +"|"+ order.get("item"); order.put("mac", HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, KEY1, data)); System.out.println("ZaloPay CreateOrder 创建的 order信息: " + order); HttpPost post=createPost(order, apiProperties.getCreate_order_url()); // 添加日志和异常处理 try (CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse res = httpClient.execute(post)) { BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent())); StringBuilder resultJsonStr = new StringBuilder(); String line; while ((line = rd.readLine()) != null) { resultJsonStr.append(line); } String responseJson = resultJsonStr.toString(); System.out.println("ZaloPay CreateOrder Response: " + responseJson); // 日志输出 return JSON.parseObject(responseJson, ZaloPayCreateOrderResponse.class); } } /** * 查询订单支付状态 * * @param appTransId 订单号 * @return 支付状态 */ public ZaloPayQueryOrderResponse queryOrderStatus(String appTransId,ZaloPayProperties.ZaloPayConfig config) throws URISyntaxException, IOException { String APP_ID = config.getApp_id(); String KEY1 = config.getKey1(); String data = APP_ID +"|"+ appTransId +"|"+ KEY1; // appid|app_trans_id|key1 String mac = HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, KEY1, data); List params = new ArrayList<>(); params.add(new BasicNameValuePair("app_id", APP_ID)); params.add(new BasicNameValuePair("app_trans_id", appTransId)); params.add(new BasicNameValuePair("mac", mac)); URIBuilder uri = new URIBuilder(apiProperties.getQuery_order_url()); uri.addParameters(params); CloseableHttpClient client = HttpClients.createDefault(); HttpPost post = new HttpPost(uri.build()); post.setEntity(new UrlEncodedFormEntity(params)); CloseableHttpResponse res = client.execute(post); BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent())); StringBuilder resultJsonStr = new StringBuilder(); String line; while ((line = rd.readLine()) != null) { resultJsonStr.append(line); } JSONObject result = JSON.parseObject(resultJsonStr.toString()); for (String key : result.keySet()) { System.out.format("%s = %s\n", key, result.get(key)); } System.out.println("ZaloPay QueryOrder Response: " + resultJsonStr); return JSON.parseObject(resultJsonStr.toString(), ZaloPayQueryOrderResponse.class); } /** * 退款 * * @param zpTransId * @param amount * @return ZaloPayRefundResponse 退款响应数据 */ public ZaloPayRefundResponse Refund(String zpTransId, long amount,String mRefundId,ZaloPayProperties.ZaloPayConfig config) throws Exception { String APP_ID = config.getApp_id(); String KEY1 = config.getKey1(); String appid = APP_ID; long timestamp = System.currentTimeMillis(); // miliseconds Map order = new HashMap() {{ put("app_id", appid); put("zp_trans_id", zpTransId); // 使用传入的 zpTransId // put("m_refund_id", getCurrentTimeString("yyMMdd") + "_" + appid + "_" + ddId); put("m_refund_id", mRefundId); put("timestamp", timestamp); put("amount", amount); // 使用传入的 amount put("description", "ZaloPay Intergration Demo"); }}; // appid|zptransid|amount|description|timestamp String data = order.get("app_id") + "|" + order.get("zp_trans_id") + "|" + order.get("amount") + "|" + order.get("description") + "|" + order.get("timestamp"); order.put("mac", HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, KEY1, data)); CloseableHttpClient client = HttpClients.createDefault(); HttpPost post = createPost(order, apiProperties.getRefund_url()); CloseableHttpResponse res = client.execute(post); BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent())); StringBuilder resultJsonStr = new StringBuilder(); String line; while ((line = rd.readLine()) != null) { resultJsonStr.append(line); } System.out.println("ZaloPay Refund Response: " + resultJsonStr.toString()); // 日志输出 // 解析响应数据为 ZaloPayRefundResponse 对象 return JSON.parseObject(resultJsonStr.toString(), ZaloPayRefundResponse.class); } /** * 查询退款状态 * * @param m_refund_id 退款单号 * @return 退款状态 */ public ZaloPayQueryRefundResponse queryRefundStatus(String m_refund_id, ZaloPayProperties.ZaloPayConfig config) throws URISyntaxException, IOException { String APP_ID = config.getApp_id(); String KEY1 = config.getKey1(); String timestamp = Long.toString(System.currentTimeMillis()); // miliseconds String data = APP_ID +"|"+ m_refund_id +"|"+ timestamp; // app_id|m_refund_id|timestamp String mac = HMACUtil.HMacHexStringEncode(HMACUtil.HMACSHA256, KEY1, data); List params = new ArrayList<>(); params.add(new BasicNameValuePair("app_id", APP_ID)); params.add(new BasicNameValuePair("m_refund_id", m_refund_id)); params.add(new BasicNameValuePair("timestamp", timestamp)); params.add(new BasicNameValuePair("mac", mac)); URIBuilder uri = new URIBuilder(apiProperties.getQuery_refund_url()); uri.addParameters(params); CloseableHttpClient client = HttpClients.createDefault(); HttpPost post = new HttpPost(uri.build()); post.setEntity(new UrlEncodedFormEntity(params)); CloseableHttpResponse res = client.execute(post); BufferedReader rd = new BufferedReader(new InputStreamReader(res.getEntity().getContent())); StringBuilder resultJsonStr = new StringBuilder(); String line; while ((line = rd.readLine()) != null) { resultJsonStr.append(line); } System.out.println("ZaloPay QueryRefund Response: " + resultJsonStr); return JSON.parseObject(resultJsonStr.toString(), ZaloPayQueryRefundResponse.class); } public static HttpPost createPost(Map order, String refundUrl) throws UnsupportedEncodingException { HttpPost post = new HttpPost(refundUrl); List params = new ArrayList<>(); for (Map.Entry e : order.entrySet()) { params.add(new BasicNameValuePair(e.getKey(), e.getValue().toString())); } post.setEntity(new UrlEncodedFormEntity(params)); return post; } }