微信支付宝添加灵枢商户,培训班报名用灵枢

This commit is contained in:
wuchunlei
2025-10-21 17:33:07 +08:00
parent a45511e0f0
commit 439ac950f3
21 changed files with 416 additions and 171 deletions

View File

@@ -67,7 +67,9 @@ public class ShiroConfig {
filterMap.put("book/task/list","anon"); // 网站接口
filterMap.put("/pay/aliPay/notify","anon"); // 支付宝回调接口
filterMap.put("/pay/payNotify","anon"); // 微信回调接口
filterMap.put("/pay/lsPayNotify","anon"); // 微信回调接口
filterMap.put("/pay/refundNotify","anon"); // 微信退款回调接口
filterMap.put("/pay/lsRefundNotify","anon"); // 微信退款回调接口
filterMap.put("/pay/paypal/receivePaypalStatus","anon"); // paypal回调接口
filterMap.put("/weChat/**","anon");
filterMap.put("/book/baseArea/getAllBaseArea","anon");//登录前获取全部区域

View File

@@ -153,7 +153,7 @@ public class BuyOrder implements Serializable {
private String buyType;
/**
* vip order point aiVip upgradeAiVip
* vip order point relearn trainingClass aiVip upgradeAiVip
*/
private String orderType;

View File

@@ -14,29 +14,30 @@ public class AliPayConfig {
* 花生appId 沙箱id 2021002161620176
*/
public static final String HS_APP_ID ="2021003191621137";
/**
* 花生应用私钥
*/
//花生应用私钥
public static final String HS_MERCHANT_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCa+oIVGBAKp+VjHIeE/IFUFWifnUWQYBPwffWEC5+EKJbqEC/wcVSfZPKXpPAB3T0c6V6yxCOMxguUZEdeRM5W93Wf0jktrtius34Xo79vgnLXsj2TtAN1ku9Qp5ebVVw+WPdpIl1nOFNwCoiaSPmwXOsVIT5MccxUvmGUDNUg8dYVoD9WHYu13O30c4vm+jYGCu7lviRqcjnEFooJ/ORocLqJbHFaTzWMGiiAYnUUSTL1BI5vhDNJDhm3B5wUZ7/j49EWQYZbV0fXlCrZRerfPLrAgXYR95P+62K9Xh8edzThTrPXmLXP9/jTqz2118ijXSoF8EgfhVD2NLCSDid3AgMBAAECggEAR3cPN0TyWMeVer+0Knn59Vkt9rSiWHJFn5el+K8Xbuz8spCmWp0YJax6Rb10Q5fOz5854PubXRYSTupzEqBt+iKApiNd5JgFKYJxudrzsysXZCm4RX00PypzmuC9g464S7Pg2yVSpv+NUlQ5K9RM96vRZ9v9i2jKjaWA/7FvMpI3auOJgrJVoSbPYNx6/QIN1b9imukCMSga9OzF66LhfzACWxJx+DzgAX+7GcfhTF8PbhytPPg9LhlfcGq2gA/TcG6zUorFz5Qy+k//g4rxIvjcPnGfcRgoT+Xgi7I8wnm3O5icIZ6k6+B+wwN3zRTBSmXwbwsgdncGA1RUhe2tAQKBgQDweYu2ij8Io/g7KCvCtVpGHqhzKxgaOZXy0nvPFXY5KFcrrapACriztCaxjvRTXm7t25KJQazICs50OvyTZL5+U3GHp/8GK7KwzZKz5NkHHMtKoKwQADBNau/nHdro4E+PnvL9ucaFX69JF4DZqiw2aDkQkDB/BablHyvuTagJgQKBgQCk++uzero6bXOxFMadLLyWTvlOJP71U1fVSf4Nou+L4ce7k2bMpSDyEDNDOUW3WOO7zz9i8mFGCTUaoX3mhC+B9UQqKZXK2rjFgZtkNDumoCTzvjuPIWTMNN6ABetiLxbq/UD0O1xwThVQNmYwTOzwMHUMkT21ynD23KXE0JL89wKBgGg1Q8YmwooMBFYeYlhOHoCkaHsAAcHbko9Xhy+GLWU3hg73gv+dpcy6FMp9GIPIOGn67NVuEGHfzPexWCLHVYWIw3n14x3ZceYML7alRSc/4xjD58xHSKdD4BJXbbXc/p1OVB5/kvfZLyyNctjgVah+Ibx7v4hL+rbveyoZnOgBAoGAG34je+giqmPc2JB2vHBdCMsmPkBqACWgSFmpLUqOkofQSdC5W7bUs6HBeR1NIc19Pam+jVWIoiwcnlB083nplMVzU3dUj9Y83iTH6T3PBug+4CM+N47ABkt1HG5gGB9yuTv0m/5cXBaW9KPsCXZ4MVpR1wNI/kc65dhFA3QiWmcCgYEA6CfUjOWe201IC332e142WfPGp7hy8p6RHrPtlXS5YnuxVsJVusyuncVdG10kPkvPHakFokqNNUW76Trf++IPnNooMP9ucYj060hYTM7JK9F0mAdx0Mo/+nDC7voXw8rBSsLZHAWfxMh/KjQ5D7L6E2S71wP6ep25hoOuuuLTnrI=";
/**
* 应用公钥
*/
//应用公钥
public static final String HS_ALI_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmvqCFRgQCqflYxyHhPyBVBVon51FkGAT8H31hAufhCiW6hAv8HFUn2Tyl6TwAd09HOlessQjjMYLlGRHXkTOVvd1n9I5La7YrrN+F6O/b4Jy17I9k7QDdZLvUKeXm1VcPlj3aSJdZzhTcAqImkj5sFzrFSE+THHMVL5hlAzVIPHWFaA/Vh2Ltdzt9HOL5vo2Bgru5b4kanI5xBaKCfzkaHC6iWxxWk81jBoogGJ1FEky9QSOb4QzSQ4ZtwecFGe/4+PRFkGGW1dH15Qq2UXq3zy6wIF2EfeT/utivV4fHnc04U6z15i1z/f406s9tdfIo10qBfBIH4VQ9jSwkg4ndwIDAQAB";
//支付宝公钥
public static final String HS_ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiVLUVTnNuq+2C1FRtcIRcG3rCgtVVulkz2QljKbPr7NNWTJJIIfGwyhNuH76s5D1lvNmn2NkuoqM0cMJCSd+W+JW9KpdQ0dgumFHCoRA/OWUoqpLvEOmm2hRMaWpvd+OQq2aPz+p+z6pqZ9SAlgUIolzrUn4idCvgIycqRaGsf1sEJFR5W+rneqtMhNYHdwemqaqnysInwshHR3cHs1AC6y/eL6pcQhaYJ5qVMIRg54/6Lr4CU114Rmph7UM9C28ulmHkFMN/DKPUDbM1+glxjzmqHQChY293Db0dlwZeiDWF3Tli2BVd6pz5KEkQlUsGeLW1O0rT9T9sxzsavxArwIDAQAB";
/**
* 支付宝公钥
* 灵枢appId 沙箱id 2021002161620176
*/
public static final String LS_APP_ID ="2021003191621137";
//灵枢应用私钥
public static final String LS_MERCHANT_PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCa+oIVGBAKp+VjHIeE/IFUFWifnUWQYBPwffWEC5+EKJbqEC/wcVSfZPKXpPAB3T0c6V6yxCOMxguUZEdeRM5W93Wf0jktrtius34Xo79vgnLXsj2TtAN1ku9Qp5ebVVw+WPdpIl1nOFNwCoiaSPmwXOsVIT5MccxUvmGUDNUg8dYVoD9WHYu13O30c4vm+jYGCu7lviRqcjnEFooJ/ORocLqJbHFaTzWMGiiAYnUUSTL1BI5vhDNJDhm3B5wUZ7/j49EWQYZbV0fXlCrZRerfPLrAgXYR95P+62K9Xh8edzThTrPXmLXP9/jTqz2118ijXSoF8EgfhVD2NLCSDid3AgMBAAECggEAR3cPN0TyWMeVer+0Knn59Vkt9rSiWHJFn5el+K8Xbuz8spCmWp0YJax6Rb10Q5fOz5854PubXRYSTupzEqBt+iKApiNd5JgFKYJxudrzsysXZCm4RX00PypzmuC9g464S7Pg2yVSpv+NUlQ5K9RM96vRZ9v9i2jKjaWA/7FvMpI3auOJgrJVoSbPYNx6/QIN1b9imukCMSga9OzF66LhfzACWxJx+DzgAX+7GcfhTF8PbhytPPg9LhlfcGq2gA/TcG6zUorFz5Qy+k//g4rxIvjcPnGfcRgoT+Xgi7I8wnm3O5icIZ6k6+B+wwN3zRTBSmXwbwsgdncGA1RUhe2tAQKBgQDweYu2ij8Io/g7KCvCtVpGHqhzKxgaOZXy0nvPFXY5KFcrrapACriztCaxjvRTXm7t25KJQazICs50OvyTZL5+U3GHp/8GK7KwzZKz5NkHHMtKoKwQADBNau/nHdro4E+PnvL9ucaFX69JF4DZqiw2aDkQkDB/BablHyvuTagJgQKBgQCk++uzero6bXOxFMadLLyWTvlOJP71U1fVSf4Nou+L4ce7k2bMpSDyEDNDOUW3WOO7zz9i8mFGCTUaoX3mhC+B9UQqKZXK2rjFgZtkNDumoCTzvjuPIWTMNN6ABetiLxbq/UD0O1xwThVQNmYwTOzwMHUMkT21ynD23KXE0JL89wKBgGg1Q8YmwooMBFYeYlhOHoCkaHsAAcHbko9Xhy+GLWU3hg73gv+dpcy6FMp9GIPIOGn67NVuEGHfzPexWCLHVYWIw3n14x3ZceYML7alRSc/4xjD58xHSKdD4BJXbbXc/p1OVB5/kvfZLyyNctjgVah+Ibx7v4hL+rbveyoZnOgBAoGAG34je+giqmPc2JB2vHBdCMsmPkBqACWgSFmpLUqOkofQSdC5W7bUs6HBeR1NIc19Pam+jVWIoiwcnlB083nplMVzU3dUj9Y83iTH6T3PBug+4CM+N47ABkt1HG5gGB9yuTv0m/5cXBaW9KPsCXZ4MVpR1wNI/kc65dhFA3QiWmcCgYEA6CfUjOWe201IC332e142WfPGp7hy8p6RHrPtlXS5YnuxVsJVusyuncVdG10kPkvPHakFokqNNUW76Trf++IPnNooMP9ucYj060hYTM7JK9F0mAdx0Mo/+nDC7voXw8rBSsLZHAWfxMh/KjQ5D7L6E2S71wP6ep25hoOuuuLTnrI=";
//应用公钥
public static final String LS_ALI_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmvqCFRgQCqflYxyHhPyBVBVon51FkGAT8H31hAufhCiW6hAv8HFUn2Tyl6TwAd09HOlessQjjMYLlGRHXkTOVvd1n9I5La7YrrN+F6O/b4Jy17I9k7QDdZLvUKeXm1VcPlj3aSJdZzhTcAqImkj5sFzrFSE+THHMVL5hlAzVIPHWFaA/Vh2Ltdzt9HOL5vo2Bgru5b4kanI5xBaKCfzkaHC6iWxxWk81jBoogGJ1FEky9QSOb4QzSQ4ZtwecFGe/4+PRFkGGW1dH15Qq2UXq3zy6wIF2EfeT/utivV4fHnc04U6z15i1z/f406s9tdfIo10qBfBIH4VQ9jSwkg4ndwIDAQAB";
//支付宝公钥
public static final String LS_ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiVLUVTnNuq+2C1FRtcIRcG3rCgtVVulkz2QljKbPr7NNWTJJIIfGwyhNuH76s5D1lvNmn2NkuoqM0cMJCSd+W+JW9KpdQ0dgumFHCoRA/OWUoqpLvEOmm2hRMaWpvd+OQq2aPz+p+z6pqZ9SAlgUIolzrUn4idCvgIycqRaGsf1sEJFR5W+rneqtMhNYHdwemqaqnysInwshHR3cHs1AC6y/eL6pcQhaYJ5qVMIRg54/6Lr4CU114Rmph7UM9C28ulmHkFMN/DKPUDbM1+glxjzmqHQChY293Db0dlwZeiDWF3Tli2BVd6pz5KEkQlUsGeLW1O0rT9T9sxzsavxArwIDAQAB";
public static final String HS_ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiVLUVTnNuq+2C1FRtcIRcG3rCgtVVulkz2QljKbPr7NNWTJJIIfGwyhNuH76s5D1lvNmn2NkuoqM0cMJCSd+W+JW9KpdQ0dgumFHCoRA/OWUoqpLvEOmm2hRMaWpvd+OQq2aPz+p+z6pqZ9SAlgUIolzrUn4idCvgIycqRaGsf1sEJFR5W+rneqtMhNYHdwemqaqnysInwshHR3cHs1AC6y/eL6pcQhaYJ5qVMIRg54/6Lr4CU114Rmph7UM9C28ulmHkFMN/DKPUDbM1+glxjzmqHQChY293Db0dlwZeiDWF3Tli2BVd6pz5KEkQlUsGeLW1O0rT9T9sxzsavxArwIDAQAB";
/**
* 回调地址 因为是内网开发 目前为内网穿透地址
*/
// public static final String NOTIFY_URL = "http://59.110.212.44:9100/pb/pay/aliPay/notify";
public static final String NOTIFY_URL = "https://api.nuttyreading.com/pay/aliPay/notify";
public static final String NOTIFY_URL = "http://z6f8f828.natappfree.cc/pb/pay/aliPay/notify";
// public static final String NOTIFY_URL = "https://api.nuttyreading.com/pay/aliPay/notify";
/**
@@ -64,19 +65,18 @@ public class AliPayConfig {
*/
public static final String GATEWAYURL = "https://openapi.alipay.com/gateway.do";
private static AlipayClient alipayClient = null;
public static AlipayClient getAliPayClient() throws AlipayApiException {
//实例化客户端
if (alipayClient == null) {
synchronized (AliPayUtil.class) {
if (null == alipayClient) {
alipayClient = new DefaultAlipayClient(GATEWAYURL, HS_APP_ID, HS_MERCHANT_PRIVATE_KEY,
FORMAT, CHARSET, HS_ALIPAY_PUBLIC_KEY, SIGN_TYPE);
}
}
public static AlipayClient getAliPayClient(String mchName) throws AlipayApiException {
if ("LS".equals(mchName)) {
return new DefaultAlipayClient(GATEWAYURL, LS_APP_ID, LS_MERCHANT_PRIVATE_KEY,
FORMAT, CHARSET, LS_ALIPAY_PUBLIC_KEY, SIGN_TYPE);
}else {
return new DefaultAlipayClient(GATEWAYURL, HS_APP_ID, HS_MERCHANT_PRIVATE_KEY,
FORMAT, CHARSET, HS_ALIPAY_PUBLIC_KEY, SIGN_TYPE);
}
return alipayClient;
}
}

View File

@@ -51,7 +51,7 @@ public class AliPayUtil {
request.setNotifyUrl(AliPayConfig.NOTIFY_URL);
try {
//这里和普通的接口调用不同使用的是sdkExecute
AlipayTradeAppPayResponse responseStr = AliPayConfig.getAliPayClient().sdkExecute(request);
AlipayTradeAppPayResponse responseStr = AliPayConfig.getAliPayClient(aliPayDto.getMchName()).sdkExecute(request);
//可以直接给客户端请求,无需再做处理。
map.put("msg", responseStr.getBody());
} catch (AlipayApiException e) {
@@ -69,7 +69,7 @@ public class AliPayUtil {
*/
public AlipayTradeWapPayResponse aliPayH5(AlipayDTO h5PayDto) {
try {
AlipayClient alipayClient = AliPayConfig.getAliPayClient();
AlipayClient alipayClient = AliPayConfig.getAliPayClient(h5PayDto.getMchName());
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setNotifyUrl(AliPayConfig.NOTIFY_URL);
request.setBizContent(getAliPayRequest(h5PayDto).toString());
@@ -108,7 +108,7 @@ public class AliPayUtil {
AlipayTradeRefundResponse response = null;
try {
response = AliPayConfig.getAliPayClient().execute(request);
response = AliPayConfig.getAliPayClient(reFundDTO.getMchName()).execute(request);
map.put("msg", response.getBody());
} catch (Exception e) {
log.info(">>>>>>>>>>退款出现异常 exception = {}", e);
@@ -121,7 +121,7 @@ public class AliPayUtil {
* 功能描述 查询订单
* @param outTradeNo
*/
public AlipayTradeQueryResponse getAliPayOrder(String outTradeNo) {
public AlipayTradeQueryResponse getAliPayOrder(String outTradeNo,String mchName) {
log.info(">>>>>>>>>查询支付宝订单 订单号 = {}", outTradeNo);
Map map = new HashMap();
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
@@ -130,7 +130,7 @@ public class AliPayUtil {
request.setBizModel(model);
AlipayTradeQueryResponse response = null;
try {
response = AliPayConfig.getAliPayClient().execute(request);
response = AliPayConfig.getAliPayClient(mchName).execute(request);
return response;
} catch (Exception e) {
log.info(">>>>>>>>>>查询订单出现异常 exception = {}", e);

View File

@@ -54,4 +54,6 @@ public class AlipayDTO {
private String customerId;
private String relevanceoid;
private String mchName;//商户名 ""为默认商户号,"ls"为灵枢商户
}

View File

@@ -40,4 +40,6 @@ public class ReFundDTO {
*/
private String outRequestNo;
private String mchName;//商户名 ""为默认商户号,"ls"为灵枢商户
}

View File

@@ -87,6 +87,15 @@ public class AliPayServiceImpl implements AliPayService {
@Override
public String pay(AlipayDTO payDto) {
Integer type = payDto.getType();
//培训班订单用灵枢商户收款
BuyOrder buyOrder = buyOrderService.getOne(new LambdaQueryWrapper<BuyOrder>()
.eq(BuyOrder::getOrderSn,payDto.getRelevanceoid()));
String mchName = "";
if (buyOrder != null && "trainingClass".equals(buyOrder.getOrderType())) {
mchName = "LS";
}
payDto.setMchName(mchName);
String orderInfo = "";
if (type == 1) {
// 走H5请求支付宝支付接口
@@ -98,7 +107,8 @@ public class AliPayServiceImpl implements AliPayService {
if (type == 2) {
// 走APP请求支付宝支付接口
log.info(">>>>>>>>>>App请求支付宝支付接口");
payDto.setOutTradeNo(OrderUtils.getOrderCode(Integer.valueOf(payDto.getCustomerId())));
// payDto.setOutTradeNo(OrderUtils.getOrderCode(Integer.valueOf(payDto.getCustomerId())));
payDto.setOutTradeNo(payDto.getRelevanceoid());
Map<String, Object> map = aliPayUtil.aliPayOrder(payDto);
Object obj = map.get("msg");
String resJson = obj.toString();
@@ -136,7 +146,13 @@ public class AliPayServiceImpl implements AliPayService {
log.info(">>>>>>>>>>支付宝回调 sign = {}, trade_status = {}, out_trade_no = {}, 参数 = {}", params.get("sign"),
params.get("trade_status"), params.get("out_trade_no"), params.toString());
//调用SDK验证签名验证是阿里回调而不是其他恶意回调
boolean flag = AlipaySignature.rsaCheckV1(params, AliPayConfig.HS_ALIPAY_PUBLIC_KEY, AliPayConfig.CHARSET, AliPayConfig.SIGN_TYPE);
BuyOrder buyOrder = buyOrderService.getOne(new LambdaQueryWrapper<BuyOrder>()
.eq(BuyOrder::getOrderSn,params.get("out_trade_no")));
String alipayPublicKey = AliPayConfig.HS_ALIPAY_PUBLIC_KEY;
if (buyOrder != null && "trainingClass".equals(buyOrder.getOrderType())) {
alipayPublicKey = AliPayConfig.LS_ALIPAY_PUBLIC_KEY;
}
boolean flag = AlipaySignature.rsaCheckV1(params, alipayPublicKey, AliPayConfig.CHARSET, AliPayConfig.SIGN_TYPE);
// log.error(">>>>>>>>>>验签结果 flag = {}", flag);
if (flag) {
log.info(">>>>>>>>>>验签通过");
@@ -380,6 +396,13 @@ public class AliPayServiceImpl implements AliPayService {
reFundDTO.setRefundAmount(new BigDecimal(params.get("refundFee").toString()));
// reFundDTO.setOutRequestNo(params.get("outRequestNo").toString());
reFundDTO.setOutRequestNo(UUID.randomUUID().toString());
BuyOrder buyOrder = buyOrderService.getOne(new LambdaQueryWrapper<BuyOrder>()
.eq(BuyOrder::getOrderSn,params.get("orderSn")));
String mchName = "";
if (buyOrder != null && "trainingClass".equals(buyOrder.getOrderType())) {
mchName = "LS";
}
reFundDTO.setMchName(mchName);
Map<String, Object> map = aliPayUtil.aliPayRefund(reFundDTO);
Object obj = map.get("msg");
String resJson = obj.toString();

View File

@@ -51,76 +51,60 @@ public class WechatPayConfig implements Serializable {
private String xlkjappId;
@Value("${wxpay.thyyappId}")
private String thyyappId;
/**
* 商户号
*/
@Value("${wxpay.mchId}")
private String mchId;
private String mchId;//商户号
@Value("${wxpay.serialNo}")
private String serialNo;//api证书序列号
@Value("${wxpay.apiV3Key}")
private String apiV3Key;//与灵枢相同
@Value("${wxpay.keyPemPath}")
private String keyPemPath;
@Value("${wxpay.privateKeyUrl}")
private String privateKeyUrl;
@Value("${wxpay.wechatPayCertificateUrl}")
private String wechatPayCertificateUrl;//平台证书,写命令获取
@Value("${wxpay.notifyUrl}")
private String notifyUrl;//付款回调
@Value("${wxpay.refundNotifyUrl}")
private String refundNotifyUrl;//退款回调
//灵枢
@Value("${wxpay.lsMchId}")
private String lsMchId;
@Value("${wxpay.lsSerialNo}")
private String lsSerialNo;
@Value("${wxpay.lsApiV3Key}")
private String lsApiV3Key;//与众妙相同
@Value("${wxpay.lsKeyPemPath}")
private String lsKeyPemPath;
@Value("${wxpay.lsPrivateKeyUrl}")
private String lsPrivateKeyUrl;
@Value("${wxpay.lsWechatPayCertificateUrl}")
private String lsWechatPayCertificateUrl;
@Value("${wxpay.lsNotifyUrl}")
private String lsNotifyUrl;
@Value("${wxpay.lsRefundNotifyUrl}")
private String lsRefundNotifyUrl;
/**
* pay url
*/
@Value("${wxpay.payUrl}")
private String payUrl;
/**
* pay url
* 退款 url
*/
@Value("${wxpay.refundUrl}")
private String refundUrl;
/**
* 回调地址
*/
@Value("${wxpay.notifyUrl}")
private String notifyUrl;
/**
* key
*/
@Value("${wxpay.apiV3Key}")
private String apiV3Key;
/**
* 退款回调地址
*/
@Value("${wxpay.refundNotifyUrl}")
private String refundNotifyUrl;
/**
* API 证书中的 key.pem 商户私钥
*/
@Value("${wxpay.keyPemPath}")
private String keyPemPath;
/**
* 商户序列号
*/
@Value("${wxpay.serialNo}")
private String serialNo;
@Value("${wxpay.wechatPayCertificateUrl}")
private String wechatPayCertificateUrl;
@Value("${wxpay.privateKeyUrl}")
private String privateKeyUrl;
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
/**
* 获取私钥
*
* @param keyPemPath
* @return
*/
public PrivateKey getPrivateKey(String keyPemPath) {
try {
return PemUtil.loadPrivateKey(ResourceUtils.getURL(keyPemPath).openStream());
} catch (FileNotFoundException e) {
throw new RuntimeException("私钥文件不存在", e);
} catch (IOException e) {
throw new RuntimeException("私钥文件流失败", e);
}
}
/**
* 获取证书管理器实例 签名验证器
@@ -141,47 +125,38 @@ public class WechatPayConfig implements Serializable {
certificatesManager.putMerchant(mchId, wechatPay2Credentials, apiV3Key.getBytes(StandardCharsets.UTF_8));
return certificatesManager.getVerifier(mchId);
}
@Bean
public Verifier getLSVerifier() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException {
log.info("获取证书管理器实例");
//获取商户私钥
PrivateKey privateKey = getPrivateKey(lsKeyPemPath);
//私钥签名对象
PrivateKeySigner privateKeySigner = new PrivateKeySigner(lsSerialNo, privateKey);
//身份认证对象
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(lsMchId, privateKeySigner);
// 使用定时更新的签名验证器,不需要传入证书
CertificatesManager certificatesManager = CertificatesManager.getInstance();
certificatesManager.putMerchant(lsMchId, wechatPay2Credentials, lsApiV3Key.getBytes(StandardCharsets.UTF_8));
return certificatesManager.getVerifier(lsMchId);
}
/**
* 获取支付http请求对象
* 获取私钥
*
* @param verifier
* @param keyPemPath
* @return
*/
@Bean(name = "wxPayClient")
public CloseableHttpClient getWxPayClient(Verifier verifier) {
log.info("获取HttpClient");
//获取商户私钥
PrivateKey privateKey = getPrivateKey(keyPemPath);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, serialNo, privateKey)
.withValidator(new WechatPay2Validator(verifier));
CloseableHttpClient httpClient = builder.build();
// 通过WechatPayHttpClientBuilder构造的HttpClient会自动的处理签名和验签并进行证书自动更新
return httpClient;
public PrivateKey getPrivateKey(String keyPemPath) {
try {
return PemUtil.loadPrivateKey(ResourceUtils.getURL(keyPemPath).openStream());
} catch (FileNotFoundException e) {
throw new RuntimeException("私钥文件不存在", e);
} catch (IOException e) {
throw new RuntimeException("私钥文件流失败", e);
}
}
/**
* 获取HttpClient无需进行应答签名验证跳过验签的流程
*/
public CloseableHttpClient getWxPayNoSignClient() {
PrivateKey privateKey = getPrivateKey(keyPemPath);
//用于构造HttpClient
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
//设置商户信息
.withMerchant(mchId, serialNo, privateKey)
//无需进行签名验证、通过withValidator((response) -> true)实现
.withValidator((response) -> true);
// 通过WechatPayHttpClientBuilder构造的HttpClient会自动的处理签名和验签并进行证书自动更新
return builder.build();
}
}

View File

@@ -80,7 +80,7 @@ public class WeChatPayController {
map.put("noncestr", nonceStr);
map.put("package", "Sign=WXPay");
paramMap.put("mchid", wechatPayConfig.getMchId());
if ("trainingClass".equals(paymentInfo.getOrderType())){
if ("trainingClass".equals(order.getOrderType())){
paramMap.put("mchid", wechatPayConfig.getLsMchId());
}
QueryWrapper<PayWechatOrderEntity> wechatOrderQueryWrapper = new QueryWrapper<>();
@@ -90,7 +90,12 @@ public class WeChatPayController {
map.put("prepayid", prepayId);
long timestamp = System.currentTimeMillis() / 1000;
map.put("timestamp", timestamp);
String sign = wxPayUtil.getSign(appid, timestamp, nonceStr, prepayId);
String sign = "";
if ("trainingClass".equals(order.getOrderType())){
sign = wxPayUtil.getSign(appid, timestamp, nonceStr, prepayId, "LS");
}else {
sign = wxPayUtil.getSign(appid, timestamp, nonceStr, prepayId, "");
}
map.put("sign", sign);
Map<String, Object> result = new HashMap<>();
result.put("paramMap", paramMap);
@@ -110,6 +115,11 @@ public class WeChatPayController {
public void payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
wxpayService.payNotify(request);
}
@PostMapping("/lsPayNotify")
@Transactional
public void lsPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
wxpayService.lsPayNotify(request);
}
/**
* 微信退款申请
@@ -127,6 +137,10 @@ public class WeChatPayController {
public void refundNotify(HttpServletRequest request){
wxpayService.refundNotify(request);
}
@PostMapping("/lsRefundNotify")
public void lsRefundNotify(HttpServletRequest request){
wxpayService.lsRefundNotify(request);
}

View File

@@ -15,8 +15,12 @@ public interface WxpayService extends IService<PayWechatOrderEntity> {
void payNotify(HttpServletRequest request) throws Exception;
void lsPayNotify(HttpServletRequest request) throws Exception;
String refund(Map<String,Object> map);
void refundNotify(HttpServletRequest request);
void lsRefundNotify(HttpServletRequest request);
}

View File

@@ -109,15 +109,16 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
paramMap.put("appid", appid);
// 商户 id
paramMap.put("mchid", wechatPayConfig.getMchId());
if ("trainingClass".equals(paymentInfo.getOrderType())){
paramMap.put("mchid", wechatPayConfig.getLsMchId());
}
// 描述
paramMap.put("description", "微信支付");
// 订单编号
paramMap.put("out_trade_no", paymentInfo.getOrderSn());
// 微信回调地址
paramMap.put("notify_url", wechatPayConfig.getNotifyUrl());
if ("trainingClass".equals(paymentInfo.getOrderType())){
paramMap.put("mchid", wechatPayConfig.getLsMchId());
paramMap.put("notify_url", wechatPayConfig.getLsNotifyUrl());
}
BigDecimal totalAmount = paymentInfo.getTotalAmount();
// 这里 * 100 单位为 ‘分’
BigDecimal hand = new BigDecimal("100");
@@ -129,7 +130,12 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
JSONObject json = JSONObject.parseObject(JSON.toJSONString(paramMap));
log.info("请求参数:{}", paramMap);
JSONObject responseJson = wxPayUtil.doPostWexinV3(wechatPayConfig.getPayUrl(), json.toJSONString());
JSONObject responseJson = null;
if ("trainingClass".equals(paymentInfo.getOrderType())){
responseJson = wxPayUtil.doPostWexinV3(wechatPayConfig.getPayUrl(), json.toJSONString(),"LS");
}else {
responseJson = wxPayUtil.doPostWexinV3(wechatPayConfig.getPayUrl(), json.toJSONString(),"");
}
String prepayId = responseJson.getString("prepay_id");
if (paymentInfo.getBuyOrderId() == null) {
payWechatOrderService.add(paymentInfo.getOrderSn(), prepayId);
@@ -144,7 +150,7 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
public void payNotify(HttpServletRequest request) throws Exception {
log.info("微信支付回调");
// 处理通知参数
Map<String, Object> bodyMap = getNotifyBody(request);
Map<String, Object> bodyMap = getNotifyBody(request,"");
// 解密resource中的通知数据
String resource = bodyMap.get("resource").toString();
Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 1);
@@ -342,6 +348,45 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
}
}
@Override
@Transactional
public void lsPayNotify(HttpServletRequest request) throws Exception {
log.info("微信支付回调");
// 处理通知参数
Map<String, Object> bodyMap = getNotifyBody(request,"LS");
// 解密resource中的通知数据
String resource = bodyMap.get("resource").toString();
Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 1);
String orderNo = resourceMap.get("out_trade_no").toString();
//修改微信订单表
MPJLambdaWrapper<PayWechatOrderEntity> wrapper = new MPJLambdaWrapper();
wrapper.eq(PayWechatOrderEntity::getOrderSn,orderNo);
PayWechatOrderEntity payWechatOrderEntity = payWechatOrderService.getOne(wrapper);
payWechatOrderEntity.setOrderId(resourceMap.get("transaction_id").toString());
payWechatOrderService.updateById(payWechatOrderEntity);
// 根据订单号,做幂等处理,并且在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱
BuyOrder order = this.buyOrderService.getOne(new QueryWrapper<BuyOrder>().eq("order_sn", orderNo));
if ("3".equals(order.getOrderStatus())){
return;
}
//使用优惠券
if (order.getCouponId()!=null&&order.getCouponId()!=0){
CouponHistory couponHistory = couponHistoryService.getById(order.getCouponId());
couponHistory.setOrderId(order.getOrderId());
couponService.useCouponAmount(couponHistory);
}
//处理抵扣积分
if(order.getJfDeduction().compareTo(BigDecimal.ZERO)>0){
userCoinJf(order);
}
if("trainingClass".equals(order.getOrderType())){
//更新 订单 记录
buyOrderService.updateOrderStatus(order.getUserId(),orderNo,"2");
//插入培训班
trainingClassService.addTrainingClassForUser(order);
}
}
@Override
public String refund(Map<String,Object> map){
LambdaQueryWrapper<PayWechatOrderEntity> wrapper = new LambdaQueryWrapper();
@@ -372,7 +417,14 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
JSONObject json = JSONObject.parseObject(JSON.toJSONString(paramMap));
log.info("微信退款申请请求参数:{}", paramMap);
log.info(">>>>>>>>>>App请求微信退款申请接口");
JSONObject responseJson = wxPayUtil.doPostWexinV3(wechatPayConfig.getRefundUrl(), json.toJSONString());
//培训班订单用灵枢商户收款
BuyOrder buyOrder = buyOrderService.getOne(new LambdaQueryWrapper<BuyOrder>()
.eq(BuyOrder::getOrderSn,map.get("orderSn").toString()));
String mchName = "";
if (buyOrder != null && "trainingClass".equals(buyOrder.getOrderType())) {
mchName = "LS";
}
JSONObject responseJson = wxPayUtil.doPostWexinV3(wechatPayConfig.getRefundUrl(), json.toJSONString(),mchName);
log.info(">>>>>>>>>>>微信退款返回的信息是 resJson = {}", responseJson.toJSONString());
if ("SUCCESS".equals(responseJson.get("status"))){
//退款申请成功,等待到账
@@ -399,7 +451,34 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
public void refundNotify(HttpServletRequest request){
log.info("微信退款回调");
// 处理通知参数
Map<String, Object> bodyMap = getNotifyBody(request);
Map<String, Object> bodyMap = getNotifyBody(request,"");
// 解密resource中的通知数据
String resource = bodyMap.get("resource").toString();
Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 2);
log.info("微信退款回调结果 msg={}",resourceMap);
if ("SUCCESS".equals(resourceMap.get("refund_status").toString())){
log.info(">>>>>>>>>>>微信退款成功!<<<<<<<<<<<<<");
MPJLambdaWrapper<BuyOrder> w = new MPJLambdaWrapper();
w.selectAll(BuyOrder.class);
w.leftJoin(PayWechatOrderEntity.class,PayWechatOrderEntity::getOrderSn, BuyOrder::getOrderSn);
w.eq("t1.order_id",resourceMap.get("transaction_id").toString());
BuyOrder order = buyOrderService.getOne(w);
PayRefundOrder refund = new PayRefundOrder();
refund.setPayType("1");
refund.setOrderId(order.getOrderId());
refund.setTradeNo(resourceMap.get("transaction_id").toString());
refund.setOutTradeNo(resourceMap.get("out_trade_no").toString());
refund.setRefundFee(((Map)resourceMap.get("amount")).get("refund").toString());
refundOrderService.save(refund);
refundOrderService.businessOpt(order);
}
}
@Override
@Transactional
public void lsRefundNotify(HttpServletRequest request){
log.info("微信退款回调");
// 处理通知参数
Map<String, Object> bodyMap = getNotifyBody(request,"LS");
// 解密resource中的通知数据
String resource = bodyMap.get("resource").toString();
Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 2);
@@ -423,7 +502,7 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
}
private Map<String, Object> getNotifyBody(HttpServletRequest request) {
private Map<String, Object> getNotifyBody(HttpServletRequest request,String mchName) {
// 处理通知参数
String body = HttpUtils.readData(request);
log.info("支付回调参数:{}", body);
@@ -434,7 +513,12 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
String notifyId = bodyMap.get("id").toString();
// 验证签名信息
try {
WechatPayValidator wechatPayValidator = new WechatPayValidator(wechatPayConfig.getVerifier(), notifyId, body);
WechatPayValidator wechatPayValidator = null;
if ("LS".equals(mchName)) {
wechatPayValidator = new WechatPayValidator(wechatPayConfig.getLSVerifier(), notifyId, body);
}else{
wechatPayValidator = new WechatPayValidator(wechatPayConfig.getVerifier(), notifyId, body);
}
if (!wechatPayValidator.validate(request)) {
log.error("通知验签失败");
return null;

View File

@@ -32,15 +32,24 @@ public class WxPayUtil {
private CloseableHttpClient httpClient;
public void setup() {
public void setup(String mchName) {
PrivateKey merchantPrivateKey = null;
X509Certificate wechatPayCertificate = null;
String privateKeyUrl = wechatPayConfig.getPrivateKeyUrl();
String wechatPayCertificateUrl = wechatPayConfig.getWechatPayCertificateUrl();
String mchId = wechatPayConfig.getMchId();
String serialNo = wechatPayConfig.getSerialNo();
if ("LS".equals(mchName)) {
privateKeyUrl = wechatPayConfig.getLsPrivateKeyUrl();
wechatPayCertificateUrl = wechatPayConfig.getLsWechatPayCertificateUrl();
mchId = wechatPayConfig.getLsMchId();
serialNo = wechatPayConfig.getLsSerialNo();
}
try {
merchantPrivateKey = PemUtil.loadPrivateKey(
new FileInputStream(wechatPayConfig.getPrivateKeyUrl()));
new FileInputStream(privateKeyUrl));
wechatPayCertificate = PemUtil.loadCertificate(
new FileInputStream(wechatPayConfig.getWechatPayCertificateUrl()));
new FileInputStream(wechatPayCertificateUrl));
} catch (FileNotFoundException e) {
e.printStackTrace();
@@ -50,7 +59,7 @@ public class WxPayUtil {
listCertificates.add(wechatPayCertificate);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(wechatPayConfig.getMchId(), wechatPayConfig.getSerialNo(), merchantPrivateKey)
.withMerchant(mchId, serialNo, merchantPrivateKey)
.withWechatPay(listCertificates);
httpClient = builder.build();
}
@@ -63,11 +72,8 @@ public class WxPayUtil {
* url 下单地址
* body 构造好的消息体
*/
public JSONObject doPostWexinV3(String url, String body) {
if (httpClient == null) {
setup();
}
public JSONObject doPostWexinV3(String url, String body, String mchName) {
setup(mchName);
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json;chartset=utf-8");
httpPost.addHeader("Accept", "application/json");
@@ -96,11 +102,11 @@ public class WxPayUtil {
}
//获取签名
public String getSign(String appId, long timestamp, String nonceStr, String pack) {
public String getSign(String appId, long timestamp, String nonceStr, String pack,String mchName) {
String message = buildMessage(appId, timestamp, nonceStr, pack);
String paySign = null;
try {
paySign = sign(message.getBytes("utf-8"));
paySign = sign(message.getBytes("utf-8"),mchName);
} catch (Exception e) {
e.printStackTrace();
}
@@ -114,16 +120,20 @@ public class WxPayUtil {
+ pack + "\n";
}
private String sign(byte[] message) throws Exception {
private String sign(byte[] message,String mchName) throws Exception {
PrivateKey merchantPrivateKey = null;
X509Certificate wechatPayCertificate = null;
String privateKeyUrl = wechatPayConfig.getPrivateKeyUrl();
String wechatPayCertificateUrl = wechatPayConfig.getWechatPayCertificateUrl();
if ("LS".equals(mchName)) {
privateKeyUrl = wechatPayConfig.getLsPrivateKeyUrl();
wechatPayCertificateUrl = wechatPayConfig.getLsWechatPayCertificateUrl();
}
try {
merchantPrivateKey = PemUtil.loadPrivateKey(
new FileInputStream(wechatPayConfig.getPrivateKeyUrl()));
new FileInputStream(privateKeyUrl));
wechatPayCertificate = PemUtil.loadCertificate(
new FileInputStream(wechatPayConfig.getWechatPayCertificateUrl()));
new FileInputStream(wechatPayCertificateUrl));
} catch (FileNotFoundException e) {
e.printStackTrace();
}