分享一些微信支付/分账后端代码及问题收录
微信支付文档值得吐槽,sdk不如第三方,网络知识付费严重,分享解决问题需要注册会员,vip和卖课程的比较多,程序开源共享以后会走下坡路,功利心已经覆盖了分享的初衷好了,继续我的个人分享,如有疑问请留言,如喜欢请关注,如有帮助请点赞微信官方支付接口地址https://pay.weixin.qq.com/wiki/doc/api/index.html代码我尽量写在一起,该需要的引入我会贴出依赖,存在的
微信官方支付接口地址:https://pay.weixin.qq.com/wiki/doc/api/index.html
导入WXPayUtil
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
统一支付https://api.mch.weixin.qq.com/pay/unifiedorder
/**
*func :微信统一支付接口
*
*date:2019-11-11
*作者:lijinquan
**//
public ResultVO<Map<String,String>> wechatProfitSharingPay( WechatPayVo payVo) throws Exception{
logger.info("微信分账支付请求预订单号===>>>wechatProfitSharingPay");
Message message = PhaseInterceptorChain.getCurrentMessage();
HttpServletRequest httpServletRequest = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
String realIp =httpServletRequest.getRemoteAddr();
ResultVO<Map<String,String>> result=new ResultVO<Map<String,String>>();
Map<String,String> repData = new HashMap<String,String>();
result.setData(repData);
//1.参数封装
Map param=new HashMap();
//公众账号ID
param.put("appid", wechatAppId);
//商户号
param.put("mch_id", wechatMerchantId);
//随机字符串
param.put("nonce_str", WXPayUtil.generateNonceStr());
param.put("body", imName);
//交易订单号
param.put("out_trade_no", outTradeNo.trim());
//金额(分)
param.put("total_fee",actualAmount.toString());
param.put("spbill_create_ip",realIp);
param.put("notify_url", wechatNotifyUrl);
//交易类型
param.put("trade_type", "JSAPI");
param.put("sign_type", "HMAC-SHA256");//分账必须只支持HMAC-SHA256,不分账可以不设置这个参数默认就为md5
param.put("profit_sharing","Y");
//用户标示
param.put("openid", payVo.getOpenid());
try {
//根据接口文档的案例要求,微信服务器接收参数方式是xml格式,所以将参数转换为xml
//WXPayConstants.SignType.HMACSHA256这个参数不传默认为MD5,可查看源码了解详情
String xmlParam = WXPayUtil.generateSignedXml(param, wechatApiKey, WXPayConstants.SignType.HMACSHA256);
logger.info("请求的参数:"+xmlParam);
xmlParam = new String(xmlParam.getBytes("UTF-8"),"ISO8859-1");
//2.发送请求
String xmlResult = HttpClientUtil.PostXml(WXPayConstants.UNIFIEDORDER_URL, xmlParam);
System.out.println(xmlResult);
Map<String, String> mapResult = WXPayUtil.xmlToMap(xmlResult);
logger.info("微信返回结果:"+mapResult);
//返回前端数据
if (mapResult.get("return_code").equals("SUCCESS")){
//返回给APP端的参数,APP端再调起支付接口
String prepay_id= mapResult.get("prepay_id");
//签名
String sign = WXPayUtil.generateSignature(repData,wechatApiKey);
repData.put("prepayId",prepay_id);
result.setData(repData);
}
} catch (Exception e) {
e.printStackTrace();
}
// return new HashMap();
return result;
}
请求参数
<xml> ?<br />
<appid>wxa5784a9179cb21b2</appid> ?<br />
<attach>SADA V-196 é?????èé???±??°é? ????¨??é??????è?°????é??? USB???? 3.5mmé?é?è??? é?è?</attach>?<br />
?<body>SADA V-196 é?????èé???±??°é? ????¨??é??????è?°????é??? USB???? 3.5mmé?é?è??? é?è?</body> ?<br />
?<mch_id>16888888</mch_id>?<br />
?<nonce_str>P2iRlOdAaUd8lfmAL8B1OCWYi5ehlwpF</nonce_str> ?<br />
?<notify_url>https://test.com/pay/wechatPayResponse?appKey=e1320097be42c5f7ce86c30552594907</notify_url> ?<out_trade_no>SO7721042273466</out_trade_no>?<br />
?<product_id>V5902B</product_id>?<br />
?<spbill_create_ip>0:0:0:0:0:0:0:1</spbill_create_ip>?<br />
?<total_fee>562</total_fee> ?<trade_type>JSAPI</trade_type>?<br />
?<openid>oLPst42jhg232Wp7bm8mQE3Ugv4</openid>?<br />
?<sign>6A15CDE322C7CA92C79A083529255B</sign></xml>
以上控制台打印的参数看着有乱码,其实不是
是这句代码
xmlParam = new String(xmlParam.getBytes("UTF-8"),"ISO8859-1");
的作用,因为中文需要处理过微信才能接收,不知其他朋友有没有尝试过中文不做编码处理就能成功调用的
返回结果
<xml><return_code>
<![CDATA[SUCCESS]]>
</return_code><return_msg><![CDATA]>
</return_msg><result_code><![CDATA[SUCCESS]]></result_code>
<mch_id><![CDATA[13332914]]></mch_id>
<appid><![CDATA[wxa2329cb2166]]></appid>
<nonce_str><![CDATA[ZmN238FocCNwiQ]]></nonce_str>
<sign><![CDATA[F38E20CACA4F2FA780E17936021D41BF4036AAB852800FD224E397A88FDEF8A7]]></sign>
<prepay_id><![CDATA[wx241104666660924a55510000]]>
</prepay_id><trade_type><![CDATA[JSAPI]]>
</trade_type></xml>
分账
官方api地址:https://pay.weixin.qq.com/wiki/doc/api/allocation_sl.php?chapter=25_1&index=1
单次分账地址https://api.mch.weixin.qq.com/secapi/pay/profitsharing
按照官方文档
进去按照流程申请得到
上微信单次分账代码,多次及其他可以仿照这个写法可以调通
/**
*@func :微信单次分账
*@data: 2019-11-11
*@auther :lijinquan
*/
public ResultVO<Map<String,Object>> wechatProfitSharing(WechatPayVo payVo){
ResultVO<Map<String,Object>> result=new ResultVO<Map<String,Object>>();
Map<String,Object> m=new HashedMap();
result.setData(m);
//1.参数封装
Map param=new HashMap();
//公众账号ID
param.put("appid", wechatAppId);
//商户号
param.put("mch_id", wechatMerchantId);
//微信支付分配的子商户号,即分账的出资商户号。
param.put("sub_mch_id", wechatMerchantId);
//随机字符串
param.put("nonce_str", WXPayUtil.generateNonceStr());
//签名类型,目前只支持HMAC-SHA256
param.put("sign_type", "HMAC-SHA256");
//微信支付订单号
param.put("transaction_id", "4200001042202104228993583353");
/**
* 服务商系统内部的分账单号,在服务商系统内部唯一
* (单次分账、多次分账、完结分账应使用不同的商户分账单号),
* 同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@
*/
param.put("out_order_no", "P001001001");
/**
* 分账接收方列表,不超过50个json对象,不能设置出资子商户作为分账接受方
点击行前的+展开字段详情
*/
List<Map> receivers=new ArrayList<Map>();
for(int i=0 ;i<1;i++){
Map receiver=new HashedMap();
/**
* -分账接收方类型
* MERCHANT_ID:商户号(mch_id或者sub_mch_id)
PERSONAL_OPENID:个人openid(由父商户APPID转换得到)
PERSONAL_SUB_OPENID: 个人sub_openid(由子商户APPID转换得到)
*/
receiver.put("type","PERSONAL_OPENID");
/**
* 类型是MERCHANT_ID时,是商户号(mch_id或者sub_mch_id)
类型是PERSONAL_OPENID时,是个人openid
类型是PERSONAL_SUB_OPENID时,是个人sub_openid
*/
receiver.put("account","oLPst4xXiA9m-MVGJBcacj1190ww");
/**
* -分账金额
* 分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
*/
receiver.put("amount",1);
/**
* -分账描述
*
* 分账的原因描述,分账账单中需要体现
*/
receiver.put("description","微信文档值得吐槽");
/**
* -分账个人接收方姓名
* 可选项,在接收方类型为个人的时可选填,若有值,会检查与 name 是否实名匹配,不匹配会拒绝分账请求
1、分账接收方类型是PERSONAL_OPENID时,是个人姓名(选传,传则校验)
*/
receiver.put("name","这人很强");
receivers.add(receiver);
}
param.put("receivers", JSON.toJSONString(receivers));
try {
String xmlParam = WXPayUtil.generateSignedXml(param, wechatApiKey, WXPayConstants.SignType.HMACSHA256);
logger.info("请求的参数:"+xmlParam);
xmlParam = new String(xmlParam.getBytes("UTF-8"),"ISO8859-1");
//2.发送请求
// String xmlResult = HttpClientUtil.PostXml(url, xmlParam);
// String s = WxUtils.httpPostRequest(url, xmlParam);
// System.out.println(xmlResult);
CloseableHttpClient httpClient = null;
CloseableHttpResponse httpResponse = null;
KeyStore keyStore = getCertificate(wechatMerchantId);
SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, wechatMerchantId.toCharArray()).build();
SSLConnectionSocketFactory sslf = new SSLConnectionSocketFactory(sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslf).build();
HttpPost httpPost = new HttpPost(profitsharingUrl);
StringEntity reqEntity = new StringEntity(xmlParam);
// 设置类型
reqEntity.setContentType("application/x-www-form-urlencoded");
httpPost.setEntity(reqEntity);
// String result = null;
httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
String resultStr = EntityUtils.toString(httpEntity, "UTF-8");
System.out.println("微信响应报文:"+resultStr);
EntityUtils.consume(httpEntity);
// m.put("xmlResult",xmlResult);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
*
* @description: 获取微信证书
* @param mch_id
* @auther: lijinquan
* @date: 2019-11-11
*/
public static KeyStore getCertificate(String mch_id){
//try-with-resources 关流
try{
FileInputStream inputStream = new FileInputStream(new File("E:\\wxtest\\wxpaySecurKey\\apiclient_cert.p12"));
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(inputStream, mch_id.toCharArray());
return keyStore;
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
问题的记录
问题一:分账接收方列表格式错误,一般情况是分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额
receiver.put("amount",1);//这个金额不能写成“1”,要直接写int类型
如果写“1”会返回以下结果
<xml>
<return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[分账接收方列表格式错误]]></return_msg>
</xml>
服务商和分账方无受理关系:返回信息如下
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<result_code><![CDATA[FAIL]]></result_code>
<err_code><![CDATA[INVALID_REQUEST]]></err_code>
<err_code_des><![CDATA[服务商和分账方无受理关系]]></err_code_des>
<mch_id><![CDATA[1607772914]]></mch_id>
<sub_mch_id><![CDATA[167772914]]></sub_mch_id>
<appid><![CDATA[wxa5784a7779cb2aa2]]></appid>
<nonce_str><![CDATA[05340b4c3533dd6]]></nonce_str>
<sign><![CDATA[163A5EEAEF4340C05AA09323E4FB845ADD74D684A3F80385F8608AB0271760]]></sign>
</xml>
处理办法:需要添加添加分账接收方https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver
注意签名与必填参数
java代码示例:
参数WechatPayVo 可以按照自己的需要添加属性
/**
* @function 添加分账账号
* @auther lijinuquan
* @param splitSharings
* @param wxPayVo
*/
@Override
public ResultVO<Map<String, String>> profitSharingAddReceiver(WechatPayVo wxPayVo) throws Exception {
ResultVO<Map<String, String>> result = new ResultVO<Map<String, String>>();
Map<String, Object> m = new HashedMap();
//1.参数封装
Map param = new HashMap();
//商户号
param.put("mch_id", wechatMerchantId);
//微信支付分配的子商户号,即分账的出资商户号。
param.put("appid", wechatAppId);
//随机字符串
param.put("nonce_str", WXPayUtil.generateNonceStr());
//签名类型,目前只支持HMAC-SHA256
param.put("sign_type", "HMAC-SHA256");
Map receiver = new HashedMap();
//分账接收方类型:MERCHANT_ID:商户号(mch_id或者sub_mch_id)PERSONAL_OPENID:个人openid
receiver.put("type", "Y".equals(wxPayVo.getIsMechat()) ? "MERCHANT_ID" : "PERSONAL_OPENID");
receiver.put("account", wxPayVo.getOpenid());
//否
// receiver.put("name", "名字");
receiver.put("relation_type", WechatConstants.USER);
//自定义分账关系
// receiver.put("custom_relation", WechatConstants.USER);
param.put("receiver", JSON.toJSONString(receiver));
try {
String xmlParam = WXPayUtil.generateSignedXml(param, wechatApiKey, WXPayConstants.SignType.HMACSHA256);
logger.info("请求的参数:" + xmlParam);
xmlParam = new String(xmlParam.getBytes("UTF-8"), "ISO8859-1");
//2.发送请求
String xmlResult = HttpClientUtil.PostXml(profitSharingAddReceiverUrl, xmlParam);
Map<String, String> mapResult = WXPayUtil.xmlToMap(xmlResult);
logger.info("返回报文:" + xmlResult);
//返回前端数据
if (mapResult.get("return_code").equals("SUCCESS")) {
//返回前端的参数,APP端再调起支付接口
String mch_id = mapResult.get("mch_id");
String appid = mapResult.get("appid");
String rcer = mapResult.get("receiver");
String nonce_str = mapResult.get("nonce_str");
String sign = mapResult.get("sign");
JSONObject rs = JSONObject.parseObject(rcer);
if (rs != null) {
String type = rs.getString("type");
String account = rs.getString("account");
String relation_type = rs.getString("relation_type");
}
result.setData(mapResult);
} else {
result.setErrorMsg(mapResult.get("err_code_des"));
result.setAck(EnumAck.Failure);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
其他接口地址https://pay.weixin.qq.com/wiki/doc/api/external/declarecustom.php?chapter=18_2
代码可参考以上
最后,感谢https://support.pay.weixin.qq.com/online-service?from=wechatpay
更多推荐
所有评论(0)