diff --git a/pom.xml b/pom.xml index cdbb910..d430497 100644 --- a/pom.xml +++ b/pom.xml @@ -194,6 +194,28 @@ 1.15 + + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + + + org.apache.httpcomponents + httpcore + 4.4.14 + + + + + org.apache.httpcomponents + httpmime + 4.5.13 + + diff --git a/sczx_singlepay.iml b/sczx_singlepay.iml deleted file mode 100644 index 988da39..0000000 --- a/sczx_singlepay.iml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/java/com/sczx/pay/mapper/OrderPayMapper.java b/src/main/java/com/sczx/pay/mapper/OrderPayMapper.java index b8e9fce..c720162 100644 --- a/src/main/java/com/sczx/pay/mapper/OrderPayMapper.java +++ b/src/main/java/com/sczx/pay/mapper/OrderPayMapper.java @@ -47,7 +47,7 @@ public interface OrderPayMapper { "where payment_id = #{paymentId} and del_flag = '0')") OrderMain getOrderStatusByOrderNo(@Param("paymentId") String paymentId); - @Update("update zc_order_main as om,zc_order_sub as os set os.transaction_id = #{refundId},os.pay_status = #{payStatus} os.amount = #{refundFee},os.update_time = #{updateTime}" + + @Update("update zc_order_main as om,zc_order_sub as os set os.transaction_id = #{refundId},os.pay_status = #{payStatus}, os.amount = #{refundFee},os.update_time = #{updateTime}" + " where om.order_id = os.order_id and os.payment_id = #{outTradeNo} and os.suborder_type = 'FD_DEPOSIT'" ) int updateSubOrderRefundStatus(@Param("outTradeNo") String outTradeNo, @Param("payStatus") String payStatus, diff --git a/src/main/java/com/sczx/pay/sdk/WXPay.java b/src/main/java/com/sczx/pay/sdk/WXPay.java index 6579de4..db46bf3 100644 --- a/src/main/java/com/sczx/pay/sdk/WXPay.java +++ b/src/main/java/com/sczx/pay/sdk/WXPay.java @@ -1,11 +1,27 @@ package com.sczx.pay.sdk; import com.sczx.pay.utils.WXPayUtil; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileInputStream; +import java.security.KeyStore; import java.util.Map; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; + +import javax.net.ssl.SSLContext; + + /** * 微信支付接口 */ @@ -180,7 +196,7 @@ public class WXPay { String xml = WXPayUtil.mapToXml(reqData); logger.info("微信支付请求URL: {}, 请求数据: {}", url, xml); - String response = httpRequest(url, xml, connectTimeoutMs, readTimeoutMs); + String response = httpsRequestWithCert(url, xml, connectTimeoutMs, readTimeoutMs); logger.info("微信支付响应数据: {}", response); return response; @@ -230,6 +246,59 @@ public class WXPay { } } + /** + * 带证书的HTTPS请求 + */ + private String httpsRequestWithCert(String url, String requestData, int connectTimeoutMs, int readTimeoutMs) throws Exception { + // 加载证书 + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + FileInputStream instream = new FileInputStream(new File(this.config.getCertPath())); + try { + keyStore.load(instream, this.config.getMchID().toCharArray()); + } finally { + instream.close(); + } + + // 创建SSL上下文 + SSLContext sslcontext = SSLContexts.custom() + .loadKeyMaterial(keyStore, this.config.getMchID().toCharArray()) + .build(); + + // 创建SSL连接工厂 + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + sslcontext, + new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"}, + null, + (hostname, session) -> true); + + // 创建HTTP客户端 + CloseableHttpClient httpclient = HttpClients.custom() + .setSSLSocketFactory(sslsf) + .build(); + + try { + // 创建POST请求 + HttpPost httpost = new HttpPost(url); + httpost.addHeader("Content-Type", "application/xml;charset=UTF-8"); + httpost.setEntity(new StringEntity(requestData, "UTF-8")); + + // 执行请求 + CloseableHttpResponse response = httpclient.execute(httpost); + try { + HttpEntity entity = response.getEntity(); + String result = EntityUtils.toString(response.getEntity(), "UTF-8"); + EntityUtils.consume(entity); + return result; + } finally { + response.close(); + } + } finally { + httpclient.close(); + } + } + + + /** * 判断支付结果 */ @@ -241,4 +310,6 @@ public class WXPay { return false; } } + + } diff --git a/src/main/java/com/sczx/pay/sdk/WXPayConfig.java b/src/main/java/com/sczx/pay/sdk/WXPayConfig.java index 8c446f9..95fc7b2 100644 --- a/src/main/java/com/sczx/pay/sdk/WXPayConfig.java +++ b/src/main/java/com/sczx/pay/sdk/WXPayConfig.java @@ -21,6 +21,8 @@ public abstract class WXPayConfig { * 获取 API 密钥 */ public abstract String getKey(); + + private String certPath; /** * 获取证书内容 @@ -40,4 +42,13 @@ public abstract class WXPayConfig { public int getHttpReadTimeoutMs() { return 8*1000; } + + + public String getCertPath() { + return certPath; + } + + public void setCertPath(String certPath) { + this.certPath = certPath; + } } diff --git a/src/main/java/com/sczx/pay/service/WechatPayService.java b/src/main/java/com/sczx/pay/service/WechatPayService.java index b49eb17..355cf35 100644 --- a/src/main/java/com/sczx/pay/service/WechatPayService.java +++ b/src/main/java/com/sczx/pay/service/WechatPayService.java @@ -20,6 +20,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.PostConstruct; +import java.io.File; import java.math.BigDecimal; import java.util.Date; import java.util.HashMap; @@ -248,27 +249,35 @@ public class WechatPayService { return errorResult; } + Map reqData = new HashMap<>(); + reqData.put("transaction_id",String.valueOf(paymentRecord.getTransactionId())); + reqData.put("out_trade_no", request.getOutTradeNo()); + reqData.put("out_refund_no", request.getOutRefundNo()); + reqData.put("total_fee", String.valueOf(paymentRecord.getTotalFee())); + reqData.put("refund_fee", String.valueOf(request.getRefundFee())); + reqData.put("notify_url",refundNotifyUrl); + + // 创建动态配置 DynamicWXPayConfig wxPayConfig = new DynamicWXPayConfig( appId, companyConfig.getMchId(), companyConfig.getApikey(), - notifyUrl + refundNotifyUrl ); + String certPath = "classpath*:cert/"+companyConfig.getMchId()+".p12"; + String certAbsolutePath = getCertAbsolutePath(certPath); + wxPayConfig.setCertPath(certAbsolutePath); + + + WXPay wxPay = new WXPay(wxPayConfig); - Map reqData = new HashMap<>(); - reqData.put("out_trade_no", request.getOutTradeNo()); - reqData.put("out_refund_no", request.getOutRefundNo()); - reqData.put("total_fee", String.valueOf(paymentRecord.getTotalFee())); - reqData.put("refund_fee", String.valueOf(request.getRefundFee())); - reqData.put("notify_url", refundNotifyUrl); - if (request.getRefundDesc() != null) { - reqData.put("refund_desc", request.getRefundDesc()); - } + + // 退款需要证书,这里调用带证书的接口 Map result = wxPay.refund(reqData); @@ -509,4 +518,43 @@ public class WechatPayService { } } + + /** + * 获取证书文件的绝对路径 + */ + private String getCertAbsolutePath(String certPath) { + try { + // 如果certPath是绝对路径,直接返回 + if (new File(certPath).isAbsolute()) { + return certPath; + } + + // 如果是相对路径,则从classpath下获取 + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + java.net.URL resource = classLoader.getResource(certPath); + + if (resource != null) { + return resource.getPath(); + } else { + // 如果在classpath中找不到,则尝试从当前类的classpath下获取 + resource = WechatPayService.class.getClassLoader().getResource(certPath); + if (resource != null) { + return resource.getPath(); + } else { + // 如果还找不到,则使用默认路径 + String defaultPath = "cert/1679965261.p12"; + resource = classLoader.getResource(defaultPath); + if (resource != null) { + return resource.getPath(); + } else { + throw new RuntimeException("无法找到证书文件: " + certPath); + } + } + } + } catch (Exception e) { + logger.error("获取证书路径失败", e); + throw new RuntimeException("获取证书路径失败: " + e.getMessage(), e); + } + } + } diff --git a/src/main/resources/cert/1679965261.p12 b/src/main/resources/cert/1679965261.p12 new file mode 100644 index 0000000..1c638a1 Binary files /dev/null and b/src/main/resources/cert/1679965261.p12 differ diff --git a/src/main/resources/cert/1685128771.p12 b/src/main/resources/cert/1685128771.p12 new file mode 100644 index 0000000..475779e Binary files /dev/null and b/src/main/resources/cert/1685128771.p12 differ diff --git a/src/main/resources/cert/1699979689.p12 b/src/main/resources/cert/1699979689.p12 new file mode 100644 index 0000000..ac52436 Binary files /dev/null and b/src/main/resources/cert/1699979689.p12 differ diff --git a/src/main/resources/cert/1702736781.p12 b/src/main/resources/cert/1702736781.p12 new file mode 100644 index 0000000..5caa54b Binary files /dev/null and b/src/main/resources/cert/1702736781.p12 differ diff --git a/src/main/resources/cert/1704580401.p12 b/src/main/resources/cert/1704580401.p12 new file mode 100644 index 0000000..9578b62 Binary files /dev/null and b/src/main/resources/cert/1704580401.p12 differ