工商银行微信支付回调问题处理

This commit is contained in:
彭勇平 2025-03-28 15:33:54 +08:00
parent 4901db65ac
commit a0e8cc603a
3 changed files with 123 additions and 35 deletions

View file

@ -1,5 +1,6 @@
package com.sqx.modules.pay.controller.app;
import com.alibaba.fastjson.JSONObject;
import com.sqx.common.utils.Result;
import com.sqx.modules.app.annotation.Login;
import com.sqx.modules.orders.entity.Orders;
@ -17,6 +18,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import java.util.Map;
/**
* @author fang
@ -143,18 +145,21 @@ public class ApiWeiXinPayController {
@PostMapping("/notifyJsApi")
@ApiOperation("微信回调")
public void notifyJsApi(HttpServletRequest req, HttpServletResponse resp) {
public void notifyJsApi(@RequestParam Map<String, String> params, HttpServletResponse resp) {
PrintWriter out = null;
try {
String result = wxService.icbcPayBack(req,3);
log.info("icbc支付回调参数: {}", JSONObject.toJSONString(params));
String result = wxService.icbcPayBack(params,3);
resp.setContentType("application/json; charset=utf-8");
out = resp.getWriter();
out.write(result);
} catch (Exception e) {
log.error("【工商银行】微信支付回调处理失败,请检查原因!!!,{}", e.getMessage());
} finally {
out.flush();
out.close();
if(out != null){
out.flush();
out.close();
}
}
// String resXml = "";
// try {
@ -192,10 +197,11 @@ public class ApiWeiXinPayController {
@PostMapping("/notifyJsApiShop")
@ApiOperation("微信回调")
public void notifyJsApiShop(HttpServletRequest req, HttpServletResponse resp) {
public void notifyJsApiShop(@RequestParam Map<String, String> params, HttpServletResponse resp) {
PrintWriter out = null;
try {
String result = wxService.icbcPayBack(req,4);
log.info("icbc支付回调参数: {}", JSONObject.toJSONString(params));
String result = wxService.icbcPayBack(params,4);
resp.setContentType("application/json; charset=utf-8");
out = resp.getWriter();
out.write(result);

View file

@ -3,9 +3,11 @@ package com.sqx.modules.pay.service;
import com.sqx.common.utils.Result;
import com.sqx.modules.orders.entity.Orders;
import com.sqx.modules.task.entity.HelpOrder;
import org.springframework.web.bind.annotation.RequestBody;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
/**
@ -26,7 +28,7 @@ public interface WxService {
String payBack(String resXml,Integer type);
String icbcPayBack(HttpServletRequest request, Integer type) throws Exception;
String icbcPayBack(@RequestBody Map<String, String> params, Integer type) throws Exception;
boolean refund(String ordersNo);

View file

@ -12,7 +12,9 @@ import com.github.wxpay.sdk.WXPayUtil;
import com.icbc.api.DefaultIcbcClient;
import com.icbc.api.IcbcApiException;
import com.icbc.api.IcbcConstants;
import com.icbc.api.UiIcbcClient;
import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1;
import com.icbc.api.request.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1;
import com.icbc.api.response.CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1;
import com.icbc.api.utils.IcbcSignature;
import com.icbc.api.utils.WebUtils;
@ -60,6 +62,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
@ -663,16 +666,19 @@ public class WxServiceImpl implements WxService {
return xmlBack;
}
private static final String ICBC_MCH_ID = "150537540002";//商户编号
private static final String ICBC_MER_PRTCL_NO = "150537540002";//收单产品协议编号
// private static final String ICBC_MCH_ID = "150537540002";//商户编号
private static final String ICBC_MCH_ID = "150537540003";//商户编号
// private static final String ICBC_MER_PRTCL_NO = "150537540004";//收单产品协议编号
private static final String ICBC_MER_PRTCL_NO = "150537540003";//收单产品协议编号
private static final String ICBC_APPID = "11000000000000051225";
private static final String MY_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCx24qZDrnPwAOwFJDmBcdEn+gkPj3tIfDi9nptHobqIPIwwZwtsQ20FxzYTG4QCcuFw4iDGb/VL4oxY4cjkWKjlAkVe6eyFdffiA2+toXK/Nu/U/UkcknHxeNE8CGyf/iV+yEwEiiWZ7zjNvXPGcWG+6IZkk4H9iOKwh2xbk3sd50em95meIxgKDOsaKoJ3VvCJs4ajNt8ly+V6B/at7qMF20XoQG7Qtmm1FCv05QVEH3JIYLg7N4TllYEAxKrTz4Wr4/qiiQ/dVRl6pxkDodJ/8UraFfYbsuOizeGZpAaj8lgkljwD9k32ov1X3GSNbG8EZTMJ7mSH5VWGI+w1Eh7AgMBAAECggEAZQwoOEFHjCK5daaZlDYgOnrnNwAtyrYH18rVT32ShR5muxCknMkE0hZ3iuQRfAc0nDC1NFbCyGoUB29WbfzBn9IRPyVb5y/Fz/fKZ1nntaXna1JV6nkMNfXV42rSmklegEeHWXpXmOwjQqwNB7bKpJ/+Pq0CrD9JfiI/IHlcyEVShNTR3SCxpye8Vkca1/HOBcI/aRLJ0t/xkKBXfkJOpUo7QLvEwhqZN0m/Z+AE84TNNscKNDiNmWDCfntFFzuFIbjYXUrkZwWNDU+LCYtOZ6/WXLrFpp2UoeVdJACBxAHqmaNSZltgavH3swDkMswSwj/gt7lK4k/U8rpp3uw3sQKBgQDW5ddgyyXoADRLyvNiqjRNBayaekdgUZwjs3mMQ9tkAuk+hWCGPNHAM+iIkSmjP5x3ajBrLKAPpN1/iJ0aloi9CAICXCoD4B/lfANc6njZxeIWKEZjV4hUYfXsGp57EHGlgDlAKk727IxfsHJeW7gq9KX5aao1qHyT8Yo8FhyzjwKBgQDT4BQ2o4rBCF0okJDJXgF9WexI3LD+N02Tfd9Yuz8zWaM5wgPw2EDPnwp7jrlA6IcCgn/xlAWCZAHzvD/CIg33BH0bqB9LDkJHHNwmCscczw55jwa2RXJfQFDSZ2lFggAB/01ByyU0ex1Px/Q+p2ykueYbWmQV8xst7ZL03Yu2VQKBgF1417fYZQKGpDibbEXsNpeR8kO3EDjLBplYxXPHSDQ2N/Hj3dpFtg5eBbTxPyUs1Af0/l5/qJdlZJrGd19LPurKAuW35OaOpBETYfsWWb6Pngl5NzSarEfX3Dn4UhrBSk1senp4bKRmu6AbhYOZbX/xrgfQeCKiyJ0pILGGBLHtAoGBAJiHXIXpPl6w8r/dMx6EOnZPYjciCZk5nvNrTnrGcj05brSJ4+RjCmVtjVJd8Se1PlykLg9wDHdOH8mj4BKWCY+m/5oFcmHKJhSjxijs4WLv/O+t85sMa8X+uzB9md+cMv09GhUfde1OJE/nFwJz7Va5LdrLO/pBRXPO8FivlYDxAoGBAKnjcXz3rDyXIQZSG7f81P7FudPeHbX4aywI9yWHzXjcHADVwniEBLxR0oE35Wu0gAcmnGB7aJxNqBgIBrc4VU8yJA896gKaneq20JCVKBcfB6EuHJwK31MF/YCA4JnHhuqaJ91JMnOWHkn/6DJlxbvIc+VDtW7czkvhgFS73JDN"; //应用私钥
private static final String APIGW_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMpjaWjngB4E3ATh+G1DVAmQnIpiPEFAEDqRfNGAVvvH35yDetqewKi0l7OEceTMN1C6NPym3zStvSoQayjYV+eIcZERkx31KhtFu9clZKgRTyPjdKMIth/wBtPKjL/5+PYalLdomM4ONthrPgnkN4x4R0+D4+EBpXo8gNiAFsNwIDAQAB";
private static final String DECIVE_INFO = "qHYmicPTZyKO452IV4A2stOozmLj2aYu";
private static final String ICBC_URL = "https://gw.open.icbc.com.cn/" ; //https://gw-sandbox.open.icbc.com.cn https://gw.open.icbc.com.cn
private Result icbcPay(Double moneys, Integer classify, Long userId, String outTradeNo, HttpServletRequest httpRequest, Integer shop) throws Exception{
UserEntity userEntity = userService.queryByUserId(userId);
String url = "https://gw.open.icbc.com.cn/" ; //https://gw-sandbox.open.icbc.com.cn https://gw.open.icbc.com.cn
String action = "api/cardbusiness/aggregatepay/b2c/online/consumepurchase/V1";
// UiIcbcClient client = new UiIcbcClient(APP_ID, IcbcConstants.SIGN_TYPE_RSA2, MY_PRIVATE_KEY, IcbcConstants.CHARSET_UTF8);
@ -680,7 +686,7 @@ public class WxServiceImpl implements WxService {
DefaultIcbcClient client = new DefaultIcbcClient(ICBC_APPID, IcbcConstants.SIGN_TYPE_RSA2, MY_PRIVATE_KEY, APIGW_PUBLIC_KEY);
CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1 request = new CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1();
request.setServiceUrl(url + action);
request.setServiceUrl(ICBC_URL + action);
CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz bizContent = new CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1.CardbusinessAggregatepayB2cOnlineConsumepurchaseRequestV1Biz();
request.setBizContent(bizContent);
@ -732,6 +738,7 @@ public class WxServiceImpl implements WxService {
CardbusinessAggregatepayB2cOnlineConsumepurchaseResponseV1 response;
try {
log.info("----调用icbc支付{}", JSONObject.toJSONString(request));
response = client.execute(request);
log.info("----调用icbc支付回调{}", JSONObject.toJSONString(response));
if (response.getReturnCode() == 0) {
@ -771,11 +778,11 @@ public class WxServiceImpl implements WxService {
}
@Override
public String icbcPayBack(HttpServletRequest request, Integer type) throws Exception {
log.info("工商支付回调:");
public String icbcPayBack(@RequestBody Map<String, String> reqParams, Integer type) throws Exception {
//接收参数
JSONObject bizContent = JSON.parseObject(request.getParameter("biz_content"));
JSONObject bizContent = JSONObject.parseObject(String.valueOf(reqParams.get("biz_content")));
String msgId = bizContent.getString("msg_id");
log.info("icbc 支付回调业务参数: {}", bizContent);
//应答参数
JSONObject responseBizContent = new JSONObject();
@ -787,10 +794,10 @@ public class WxServiceImpl implements WxService {
String transactionId = bizContent.getString("third_trade_no");
String appid = type == 3 ? commonInfoService.findOne(45).getValue() : commonInfoService.findOne(239).getValue();
String notifyUrl = (type == 3 ? "/sqx_fast/app/wxPay/notifyJsApiShop" : "/sqx_fast/app/wxPay/notifyJsApi");
String notifyUrl = (type == 3 ? "/sqx_fast/app/wxPay/notifyJsApi" : "/sqx_fast/app/wxPay/notifyJsApiShop");
//返回码
String returnCode = bizContent.getString("return_code");
if (this.icbcCheckSign(request, notifyUrl)) {
if (this.icbcCheckSign(reqParams, notifyUrl)) {
if ("0".equals(returnCode)) {
// log.error("微信支付订单号" + notifyMap.get("transaction_id"));
// String transactionId = notifyMap.get("transaction_id");
@ -964,6 +971,7 @@ public class WxServiceImpl implements WxService {
responseBizContent.put("return_code", 0);
responseBizContent.put("return_msg", "success");
}else {
log.info("icbc支付回调签名错误");
responseBizContent.put("return_code", -1);
responseBizContent.put("return_msg", "icbc sign not pass.");
}
@ -979,23 +987,78 @@ public class WxServiceImpl implements WxService {
return resp.toJSONString();
}
private boolean icbcCheckSign(HttpServletRequest request, String path) {
private Result icbcPayUI(Double moneys, Integer classify, Long userId, String outTradeNo, HttpServletRequest httpRequest, Integer shop) throws Exception{
UserEntity userEntity = userService.queryByUserId(userId);
//回调
String notifyUrl = commonInfoService.findOne(19).getValue() + (shop != null ? "/sqx_fast/app/wxPay/notifyJsApiShop" : "/sqx_fast/app/wxPay/notifyJsApi");
//微信商户号mchId
String mchId = commonInfoService.findOne(76).getValue();
//openid
String openId = shop != null ? userEntity.getShopOpenId() : userEntity.getOpenId();
//商户appid
String mchAppid = shop != null ? commonInfoService.findOne(239).getValue() : commonInfoService.findOne(45).getValue();
//后台服务名称
String name = commonInfoService.findOne(12).getValue();
//订单金额
String money = String.valueOf(AmountCalUtils.mul(moneys, 100).intValue());
UiIcbcClient client = new UiIcbcClient(ICBC_APPID, IcbcConstants.SIGN_TYPE_RSA2, MY_PRIVATE_KEY, IcbcConstants.CHARSET_UTF8);
CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1 request = new CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1();
//根据测试环境和生产环境替换相应ip和端口
request.setServiceUrl(ICBC_URL + "ui/cardbusiness/aggregatepay/b2c/online/ui/consumepurchaseshowpay/V1");
CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1Biz bizContent = new CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1.CardbusinessAggregatepayB2cOnlineUiConsumepurchaseshowpayRequestV1Biz();
request.setBizContent(bizContent);
// bizContent.setAttach("");
bizContent.setBody(name); //微信商品描述
bizContent.setIcbc_appid(ICBC_APPID);
bizContent.setMer_id(ICBC_MCH_ID);
bizContent.setMer_prtcl_no(ICBC_MER_PRTCL_NO);
// bizContent.setMer_acct("");
// bizContent.setNotify_type("");
bizContent.setNotify_url(notifyUrl);
bizContent.setOpenId(openId);
bizContent.setOrder_amt(money);
bizContent.setOut_trade_no(outTradeNo);
// bizContent.setPay_limit("");
// bizContent.setResult_type("");
// bizContent.setReturn_url("");
bizContent.setSaledepname(name); // 门店名称
// bizContent.setSubject("");
bizContent.setShop_appid(mchAppid);
// bizContent.setOrder_apd_inf("");
// bizContent.setDetail(name);
// bizContent.setCust_name("xxx");
// bizContent.setCust_cert_type("x");
// bizContent.setCust_cert_no("xxxx");
// bizContent.setGoods_tag("xxx");
bizContent.setStart_datetime(DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
bizContent.setExpireTime("120");
String result = "";
try {
result = client.buildPostForm(request);
} catch (IcbcApiException e) {
return Result.error("获取订单失败" + e.getMessage());
}
return Result.success().put("data", result);
}
private boolean icbcCheckSign(Map<String, String> reqParams, String path) {
Map<String, String> params = new HashMap<>();
String sign = request.getParameter("sign");
params.put("from", request.getParameter("from"));
params.put("api", request.getParameter("api"));
params.put("app_id", request.getParameter("app_id"));
params.put("charset", request.getParameter("charset"));
params.put("format", request.getParameter("format"));
params.put("timestamp", request.getParameter("timestamp"));
params.put("biz_content", request.getParameter("biz_content"));
String sign = reqParams.get("sign");
params.put("from", reqParams.get("from"));
params.put("api", reqParams.get("api"));
params.put("app_id", reqParams.get("app_id"));
params.put("charset", reqParams.get("charset"));
params.put("format", reqParams.get("format"));
params.put("timestamp", reqParams.get("timestamp"));
params.put("biz_content", reqParams.get("biz_content"));
//目前上行网关签名暂时仅支持RSA
params.put("sign_type", request.getParameter("sign_type"));
params.put("sign_type", reqParams.get("sign_type"));
String signStr= WebUtils.buildOrderedSignStr(path, params);
try {
//注意此次用的是RSA和下单时不一样
return IcbcSignature.verify(signStr, IcbcConstants.SIGN_TYPE_RSA, APIGW_PUBLIC_KEY, request.getParameter("charset"), sign);
return IcbcSignature.verify(signStr, IcbcConstants.SIGN_TYPE_RSA, APIGW_PUBLIC_KEY, reqParams.get("charset"), sign);
} catch (IcbcApiException e) {
return false;
}
@ -1138,13 +1201,30 @@ public class WxServiceImpl implements WxService {
}
public static void main(String[] args) {
String timestamp = DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss");
String rawToken = "100000002" + "2ry7EXwNHE3zOtUpEUqj1BdkFGuIna67TmKExNxG" + "1740728660";
String hashedToken = DigestUtil.sha256Hex(rawToken);
String encodedToken = cn.hutool.core.codec.Base64.encode(hashedToken);
System.out.println(System.currentTimeMillis()/1000);
System.out.println(hashedToken);
System.out.println(encodedToken);
public static void main(String[] args) throws IcbcApiException {
String notifyUrl = (true ? "/sqx_fast/app/wxPay/notifyJsApi" : "/sqx_fast/app/wxPay/notifyJsApiShop");
String jsonStr = "{\"api\":\"/api/cardbusiness/aggregatepay/b2c/online/consumepurchase/V1\",\"app_id\":\"11000000000000051225\",\"biz_content\":\"{\\\"access_type\\\":\\\"9\\\",\\\"attach\\\":\\\"\\\",\\\"bank_disc_amt\\\":\\\"0\\\",\\\"card_flag\\\":\\\"\\\",\\\"card_kind\\\":\\\"\\\",\\\"card_no\\\":\\\"\\\",\\\"coupon_amt\\\":\\\"0\\\",\\\"cust_id\\\":\\\"\\\",\\\"decr_flag\\\":\\\"\\\",\\\"ecoupon_amt\\\":\\\"0\\\",\\\"mer_disc_amt\\\":\\\"0\\\",\\\"mer_id\\\":\\\"150537540003\\\",\\\"msg_id\\\":\\\"050200155087883006188152791\\\",\\\"open_id\\\":\\\"ow8NuxGas0u7FrZkg-DWi-F1ABwM\\\",\\\"order_id\\\":\\\"150537540003000522503280002157\\\",\\\"out_trade_no\\\":\\\"1000001823360698\\\",\\\"pay_time\\\":\\\"20250328150403\\\",\\\"pay_type\\\":\\\"9\\\",\\\"payment_amt\\\":\\\"10\\\",\\\"point_amt\\\":\\\"0\\\",\\\"return_code\\\":\\\"0\\\",\\\"return_msg\\\":\\\"交易成功\\\",\\\"third_party_coupon_amt\\\":\\\"0\\\",\\\"third_party_discount_amt\\\":\\\"0\\\",\\\"third_trade_no\\\":\\\"4200002667202503283423055973\\\",\\\"total_amt\\\":\\\"10\\\",\\\"total_disc_amt\\\":\\\"0\\\"}\",\"charset\":\"UTF-8\",\"format\":\"json\",\"from\":\"icbc-api\",\"sign\":\"H1wXn/2399BQr3FOpbqdGkNCpiSbi3njGdXsWV5x8nGEzMR+CTuO8ynB+KbsVivmeHX3UERZe0Z1mAtwibIZsJ1S7Li3Hl+XwdjHbBDi7Nkpj/ZHN0iEY7NK4X+b87ZuA2edXjr5Fo2btj7yjPNwr9c5C0C7madncHRziWidjFg=\",\"sign_type\":\"RSA\",\"timestamp\":\"2025-03-28 15:05:56\"}";
JSONObject reqParams = JSONObject.parseObject(jsonStr);
// System.out.println(jsonObject.getJSONObject("biz_content"));
Map<String, String> params = new HashMap<>();
String sign = reqParams.getString("sign");
params.put("from", reqParams.getString("from"));
params.put("api", reqParams.getString("api"));
params.put("app_id", reqParams.getString("app_id"));
params.put("charset", reqParams.getString("charset"));
params.put("format", reqParams.getString("format"));
params.put("timestamp", reqParams.getString("timestamp"));
params.put("biz_content", reqParams.getString("biz_content"));
// //目前上行网关签名暂时仅支持RSA
params.put("sign_type", reqParams.getString("sign_type"));
System.out.println(params);
//
String signStr= WebUtils.buildOrderedSignStr(notifyUrl, params);
System.out.println(signStr);
Boolean flag = IcbcSignature.verify(signStr, IcbcConstants.SIGN_TYPE_RSA, APIGW_PUBLIC_KEY, reqParams.getString("charset"), sign);
System.out.println(flag);
}
}