package com.ruoyi.payment.infrastructure.channel.alipay; import com.ruoyi.payment.infrastructure.config.AlipayConfig; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.math.BigDecimal; /** * 支付宝第三方接口客户端 * 调用旧系统的支付宝当面付接口 * * @author ruoyi */ @Slf4j @Component public class AlipayThirdPartyClient { @Autowired private AlipayConfig alipayConfig; /** * 第三方支付宝当面付接口地址 */ // private String THIRD_PARTY_ALIPAY_URL = "https://sys.966120.com.cn/alipay_pay_QR_NotifyUrl.php"; /** * 第三方支付宝查询接口地址 */ private static final String THIRD_PARTY_QUERY_URL = "https://sys.966120.com.cn/alipay_pay_query.php"; /** * 调用第三方接口生成支付宝当面付URL * * @param notifyUrl 异步回调通知地址 * @param outTradeNo 商户订单号 * @param totalFee 订单金额(单位:分) * @param serviceOrdId 业务订单ID * @return 支付宝当面付URL * @throws Exception 调用异常 */ public String createQrCodeUrl(String notifyUrl, String outTradeNo, Integer totalFee, String serviceOrdId) throws Exception { log.info("调用第三方支付宝当面付接口,订单号: {}, 金额: {}分, 业务订单ID: {}", outTradeNo, totalFee, serviceOrdId); try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost(this.alipayConfig.getThirdParty().getUrl()); // 设置Cookie头 httpPost.setHeader("Cookie", "CAMEName="); BigDecimal totalFeeYuan = BigDecimal.valueOf(totalFee / 100f); // 构建multipart/form-data请求体 HttpEntity entity = MultipartEntityBuilder.create() .addTextBody("notify_url", notifyUrl) .addTextBody("out_trade_no", outTradeNo) .addTextBody("total_fee", String.valueOf(totalFeeYuan)) .addTextBody("ServiceOrdID", serviceOrdId) .build(); httpPost.setEntity(entity); log.info("发送请求到第三方接口: {}", this.alipayConfig.getThirdParty().getUrl()); // 发送请求 try (CloseableHttpResponse response = httpClient.execute(httpPost)) { int statusCode = response.getStatusLine().getStatusCode(); String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8"); log.info("第三方接口响应,状态码: {}, 响应内容: {}", statusCode, responseBody); if (statusCode >= 200 && statusCode < 300) { // 响应成功,解析返回的URL String qrCodeUrl = parseQrCodeUrl(responseBody); if (qrCodeUrl == null || qrCodeUrl.isEmpty()) { throw new Exception("第三方接口未返回有效的支付URL,响应: " + responseBody); } log.info("第三方支付宝当面付URL生成成功: {}", qrCodeUrl); return qrCodeUrl; } else { throw new Exception("第三方接口调用失败,状态码: " + statusCode + ", 响应: " + responseBody); } } } catch (Exception e) { log.error("调用第三方支付宝当面付接口失败", e); throw new Exception("调用第三方支付宝当面付接口失败: " + e.getMessage(), e); } } /** * 解析第三方接口响应,提取支付URL * 根据实际返回格式调整解析逻辑 * * @param responseBody 响应内容 * @return 支付URL */ private String parseQrCodeUrl(String responseBody) { // TODO: 根据实际返回格式调整解析逻辑 // 这里假设直接返回URL字符串,或者返回JSON格式 if (responseBody == null || responseBody.isEmpty()) { return null; } // 去除可能的引号和空白字符 String url = responseBody.trim(); if (url.startsWith("\"") && url.endsWith("\"")) { url = url.substring(1, url.length() - 1); } // 如果是JSON格式,可以使用FastJSON解析 // 示例:{"status": "success", "qr_code": "https://..."} // JSONObject json = JSON.parseObject(responseBody); // return json.getString("qr_code"); return url; } /** * 查询支付宝交易状态 * * @param outTradeNo 商户订单号 * @return 交易状态(SUCCESS-成功,其他-失败或处理中) * @throws Exception 调用异常 */ public String queryTradeStatus(String outTradeNo) throws Exception { log.info("调用第三方支付宝查询接口,订单号: {}", outTradeNo); try (CloseableHttpClient httpClient = HttpClients.createDefault()) { HttpPost httpPost = new HttpPost(THIRD_PARTY_QUERY_URL); // 设置Cookie头 httpPost.setHeader("Cookie", "CAMEName="); // 构建multipart/form-data请求体 HttpEntity entity = MultipartEntityBuilder.create() .addTextBody("out_trade_no", outTradeNo) .build(); httpPost.setEntity(entity); log.info("发送查询请求到第三方接口: {}", THIRD_PARTY_QUERY_URL); // 发送请求 try (CloseableHttpResponse response = httpClient.execute(httpPost)) { int statusCode = response.getStatusLine().getStatusCode(); String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8"); log.info("第三方查询接口响应,状态码: {}, 响应内容: {}", statusCode, responseBody); if (statusCode >= 200 && statusCode < 300) { // 响应成功,解析交易状态 String tradeStatus = parseTradeStatus(responseBody); log.info("第三方支付宝交易查询成功,订单号: {}, 状态: {}", outTradeNo, tradeStatus); return tradeStatus; } else { throw new Exception("第三方查询接口调用失败,状态码: " + statusCode + ", 响应: " + responseBody); } } } catch (Exception e) { log.error("调用第三方支付宝查询接口失败", e); throw new Exception("调用第三方支付宝查询接口失败: " + e.getMessage(), e); } } /** * 解析交易状态 * * @param responseBody 响应内容 * @return 交易状态 */ private String parseTradeStatus(String responseBody) { if (responseBody == null || responseBody.isEmpty()) { return "UNKNOWN"; } // 去除空白字符 String status = responseBody.trim(); // 去除可能的引号 if (status.startsWith("\"") && status.endsWith("\"")) { status = status.substring(1, status.length() - 1); } // 转换为大写 status = status.toUpperCase(); log.info("解析交易状态: {}", status); return status; } }