微信支付:springboot企业付款到个人银行卡
第一次做这个功能,坑有点多(官方坑也有),最终完全了付款到银行卡功能,一一为大家踩坑。文章只讲解关于转账至银行卡的业务逻辑,需要用到的工具类,还有具体做法都会贴,适合第一次开发此功能的人看。
官方文档:
【微信支付】付款开发者文档
一、准备
1.证书
按照文档操作,得到apiclient_cert.p12文件,将他放到项目内的resources/static内,如果要部署jar到云服务器的,可以把证书放在项目同文件。后面访问时需要证书路径。
2.rsa公钥文件
看文档内获取rsa公钥的文档,准备好请求参数,直接用postman请求,参数中随机值(自己生产也好,随便敲也好,跟示例参数一样多位的随机值就行),sign参数(用签名工具类把几个参数签下名)
签名方式和支付功能一样,可以直接用之前开发支付用的工具类,啥?之前没做支付,没有工具类?
那我贴一下吧:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Document;
import org.w3c.dom.Element;import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.*;/*** 微信支付要用到的:xml解析工具类*/
public class WXPayUtils {/*** XML格式字符串转换为Map** @param strXML XML字符串* @return XML数据转换后的Map* @throws Exception*/public static Map<String, String> xmlToMap(String strXML) throws Exception {try {Map<String, String> data = new HashMap<String, String>();DocumentBuilder documentBuilder = WXPayXmlUtil.newDocumentBuilder();InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));org.w3c.dom.Document doc = documentBuilder.parse(stream);doc.getDocumentElement().normalize();NodeList nodeList = doc.getDocumentElement().getChildNodes();for (int idx = 0; idx < nodeList.getLength(); ++idx) {Node node = nodeList.item(idx);if (node.getNodeType() == Node.ELEMENT_NODE) {org.w3c.dom.Element element = (org.w3c.dom.Element) node;data.put(element.getNodeName(), element.getTextContent());}}try {stream.close();} catch (Exception ex) {// do nothing}return data;} catch (Exception ex) {WXPayUtils.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);throw ex;}}/*** 将Map转换为XML格式的字符串** @param data Map类型数据* @return XML格式的字符串* @throws Exception*/public static String mapToXml(Map<String, String> data) throws Exception {Document document = WXPayXmlUtil.newDocument();Element root = document.createElement("xml");document.appendChild(root);for (String key: data.keySet()) {String value = data.get(key);if (value == null) {value = "";}value = value.trim();Element filed = document.createElement(key);filed.appendChild(document.createTextNode(value));root.appendChild(filed);}TransformerFactory tf = TransformerFactory.newInstance();Transformer transformer = tf.newTransformer();DOMSource source = new DOMSource(document);transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");transformer.setOutputProperty(OutputKeys.INDENT, "yes");StringWriter writer = new StringWriter();StreamResult result = new StreamResult(writer);transformer.transform(source, result);String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");try {writer.close();}catch (Exception ex) {}return output;}/*** 生成微信支付sign*/public static String createSign(SortedMap<String, String> params, String key){StringBuilder sb = new StringBuilder();Set<Map.Entry<String, String>> es = params.entrySet();Iterator<Map.Entry<String, String>> it = es.iterator();while(it.hasNext()){Map.Entry<String, String> entry = it.next();String k = entry.getKey();String v = entry.getValue();if(null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)){sb.append(k + "=" + v + "&");}}sb.append("key=").append(key);String sign = CommonUtils.MD5(sb.toString()).toUpperCase();return sign;}/*** 校验签名* @param params* @param key* @return*/public static Boolean isCorrectSign(SortedMap<String, String> params, String key){String sign = createSign(params, key);String wxPaySign = params.get("sign").toUpperCase();return wxPaySign.equals(sign);}/*** 获取有序map* @param map*/public static SortedMap<String, String> getSortedMap(Map<String, String> map){SortedMap<String, String> sortedMap = new TreeMap<>();Iterator<String> it = map.keySet().iterator();while(it.hasNext()){String key = it.next();String value = map.get(key);String temp = "";if(null != value){temp = value.trim();}sortedMap.put(key, value);}return sortedMap;}/*** 日志* @return*/public static Logger getLogger() {Logger logger = LoggerFactory.getLogger("wxpay java sdk");return logger;}/*** 获取当前时间戳,单位秒* @return*/public static long getCurrentTimestamp() {return System.currentTimeMillis()/1000;}/*** 获取当前时间戳,单位毫秒* @return*/public static long getCurrentTimestampMs() {return System.currentTimeMillis();}/*** 生成UUID(用来表示一笔订单)* @return*/public static String generateUUID(){String uuid = UUID.randomUUID().toString().replaceAll("-","").substring(0,32);return uuid;}
}
——签好名就请求获取rsa公钥接口,拿到了RSA公钥字符串。
——不要高兴得太早,请把这个字符串复制进txt,名字随意英文,然后改后缀名.pem,因为你是Java你需要转pkcs#8
文档内有互转的方法:
openssl rsa -RSAPublicKey_in -in <filename> -pubout
——如果没有openssl,你需要安装并配置openssl,这个可以百度。安装好后配置环境变量,然后在bin路径输入cmd,再跑上面的代码,成功之后,转换结果会直接显示在命令行,请复制这些密钥字符串。
——接下来,删除首尾:-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----
——然后将剩下的字符串放进txt,该后缀名pem,再放进项目的resources/static内。
——截止目前,我们便得到了rsa公钥文件:rsa.pem
3.银行卡开户行代号(付款至银行卡需要微信自己的参数)
这个我觉得不用说那么详细了,我自己用的方式都很业余。我是从百度找到了一个阿里的开发性api,用于获取银行卡开户行,然后再把微信的代号填到对照表里。再整理成工具类,把银行卡号做参数就可以得出代号(有几个小银行没有在对照表里),从优化的角度来看,这种方式需要跨域请求,最好是用一种可以直接识别银行卡号开户行的工具类,然后把微信开户行代号表和工具类的银行名称对齐一下。这里就默认你已经获取了银行卡开户行代号。
二、入参准备
——商户号:自行获取
——商户订单号:在请求这个接口前,你需要先新增一个你目前系统的订单,就是在订单表里插入一条订单,这个订单号就是商户订单号。
——随机值:直接调用我上方的工具类,有个generateUUID()函数直接获取。
——银行卡号:这个就需要用rsa公钥加密了。你已经有了公钥文件,但需要转成PublicKey类才能使用我的加密工具类。下面分步叙述流程(结果将得到PublicKey文件):
1.获取公钥文件的字节输入流
InputStream rsaStream = getClass().getClassLoader().getResourceAsStream(RSA公钥文件的路径字符串);
2.用下面这个工具类转成字符串
import java.io.ByteArrayOutputStream;
import java.io.InputStream;/*IO流工具类*/
public class StreamUtil {/*** 读取 InputStream 到 String字符串中*/public static String readStream(InputStream in) {try {//<1>创建字节数组输出流,用来输出读取到的内容ByteArrayOutputStream baos = new ByteArrayOutputStream();//<2>创建缓存大小byte[] buffer = new byte[1024]; // 1KB//每次读取到内容的长度int len = -1;//<3>开始读取输入流中的内容while ((len = in.read(buffer)) != -1) { //当等于-1说明没有数据可以读取了baos.write(buffer, 0, len); //把读取到的内容写到输出流中}//<4> 把字节数组转换为字符串String content = baos.toString();//<5>关闭输入流和输出流in.close();baos.close();//<6>返回字符串结果return content;} catch (Exception e) {e.printStackTrace();return e.getMessage();}}
}
3.再用下面这个工具类getPublicKey(String key)函数将公钥字符串转为PublicKey类(该工具类包含RSA加密方法)
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;import javax.crypto.Cipher;
import sun.misc.BASE64Decoder;public class RSAwxUtil {public static byte[] decrypt(byte[] encryptedBytes, PrivateKey privateKey, int keyLength, int reserveSize, String cipherAlgorithm) throws Exception {int keyByteSize = keyLength / 8;int decryptBlockSize = keyByteSize - reserveSize;int nBlock = encryptedBytes.length / keyByteSize;ByteArrayOutputStream outbuf = null;try {Cipher cipher = Cipher.getInstance(cipherAlgorithm);cipher.init(Cipher.DECRYPT_MODE, privateKey);outbuf = new ByteArrayOutputStream(nBlock * decryptBlockSize);for (int offset = 0; offset < encryptedBytes.length; offset += keyByteSize) {int inputLen = encryptedBytes.length - offset;if (inputLen > keyByteSize) {inputLen = keyByteSize;}byte[] decryptedBlock = cipher.doFinal(encryptedBytes, offset, inputLen);outbuf.write(decryptedBlock);}outbuf.flush();return outbuf.toByteArray();} catch (Exception e) {throw new Exception("DEENCRYPT ERROR:", e);} finally {try{if(outbuf != null){outbuf.close();}}catch (Exception e){outbuf = null;throw new Exception("CLOSE ByteArrayOutputStream ERROR:", e);}}}public static byte[] encrypt(byte[] plainBytes, PublicKey publicKey, int keyLength, int reserveSize, String cipherAlgorithm) throws Exception {int keyByteSize = keyLength / 8;int encryptBlockSize = keyByteSize - reserveSize;int nBlock = plainBytes.length / encryptBlockSize;if ((plainBytes.length % encryptBlockSize) != 0) {nBlock += 1;}ByteArrayOutputStream outbuf = null;try {Cipher cipher = Cipher.getInstance(cipherAlgorithm);cipher.init(Cipher.ENCRYPT_MODE, publicKey);outbuf = new ByteArrayOutputStream(nBlock * keyByteSize);for (int offset = 0; offset < plainBytes.length; offset += encryptBlockSize) {int inputLen = plainBytes.length - offset;if (inputLen > encryptBlockSize) {inputLen = encryptBlockSize;}byte[] encryptedBlock = cipher.doFinal(plainBytes, offset, inputLen);outbuf.write(encryptedBlock);}outbuf.flush();return outbuf.toByteArray();} catch (Exception e) {throw new Exception("ENCRYPT ERROR:", e);} finally {try{if(outbuf != null){outbuf.close();}}catch (Exception e){outbuf = null;throw new Exception("CLOSE ByteArrayOutputStream ERROR:", e);}}}public static PrivateKey getPriKey(String privateKeyPath,String keyAlgorithm){PrivateKey privateKey = null;InputStream inputStream = null;try {if(inputStream==null){System.out.println("hahhah1!");}inputStream = new FileInputStream(privateKeyPath);System.out.println("hahhah2!");privateKey = getPrivateKey(inputStream,keyAlgorithm);System.out.println("hahhah3!");} catch (Exception e) {System.out.println("加载私钥出错!");} finally {if (inputStream != null){try {inputStream.close();}catch (Exception e){System.out.println("加载私钥,关闭流时出错!");}}}return privateKey;}public static PublicKey getPubKey(String publicKeyPath,String keyAlgorithm){PublicKey publicKey = null;InputStream inputStream = null;try{System.out.println("getPubkey 1......");inputStream = new FileInputStream(publicKeyPath);System.out.println("getPubkey 2......");publicKey = getPublicKey(inputStream,keyAlgorithm);System.out.println("getPubkey 3......");} catch (Exception e) {e.printStackTrace();//EAD PUBLIC KEY ERRORSystem.out.println("加载公钥出错!");} finally {if (inputStream != null){try {inputStream.close();}catch (Exception e){System.out.println("加载公钥,关闭流时出错!");}}}return publicKey;}public static PublicKey getPublicKey(InputStream inputStream, String keyAlgorithm) throws Exception {try{System.out.println("b1.........");BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));System.out.println("b2.........");StringBuilder sb = new StringBuilder();String readLine = null;System.out.println("b3.........");while ((readLine = br.readLine()) != null) {if (readLine.charAt(0) == '-') {continue;} else {sb.append(readLine);sb.append('\r');}}System.out.println("b4.........");X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(decodeBase64(sb.toString()));System.out.println("b5.........");KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);System.out.println("b6.........");//下行出错 java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=127, too big.PublicKey publicKey = keyFactory.generatePublic(pubX509);System.out.println("b7.........");return publicKey;} catch (Exception e) {e.printStackTrace();System.out.println("b8.........");throw new Exception("1这里报异常了:"+e.getMessage(), e);} finally {try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {inputStream = null;throw new Exception("INPUT STREAM CLOSE ERROR:", e);}}}public static PrivateKey getPrivateKey(InputStream inputStream, String keyAlgorithm) throws Exception {try {BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));StringBuilder sb = new StringBuilder();String readLine = null;while ((readLine = br.readLine()) != null) {if (readLine.charAt(0) == '-') {continue;} else {sb.append(readLine);sb.append('\r');}}System.out.println("hahhah4!"+decodeBase64(sb.toString()));PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(decodeBase64(sb.toString()));System.out.println("hahhah5!");KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);System.out.println("hahhah6!");PrivateKey privateKey = keyFactory.generatePrivate(priPKCS8);System.out.println("hahhah7!");return privateKey;} catch (Exception e) {throw new Exception("READ PRIVATE KEY ERROR:" ,e);} finally {try {if (inputStream != null) {inputStream.close();}} catch (IOException e) {inputStream = null;throw new Exception("INPUT STREAM CLOSE ERROR:", e);}}}//一下面是base64的编码和解码public static String encodeBase64(byte[]input) throws Exception{Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");Method mainMethod= clazz.getMethod("encode", byte[].class);mainMethod.setAccessible(true);Object retObj=mainMethod.invoke(null, new Object[]{input});return (String)retObj;}/**** decode by Base64*/public static byte[] decodeBase64(String input) throws Exception{Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");Method mainMethod= clazz.getMethod("decode", String.class);mainMethod.setAccessible(true);Object retObj=mainMethod.invoke(null, input);return (byte[])retObj;}public static PublicKey getPublicKey(String key) throws Exception {byte[] keyBytes;keyBytes = (new BASE64Decoder()).decodeBuffer(key);X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey publicKey = keyFactory.generatePublic(keySpec);return publicKey;}public static PrivateKey getPrivateKey(String key) throws Exception {byte[] keyBytes;keyBytes = (new BASE64Decoder()).decodeBuffer(key);PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PrivateKey privateKey = keyFactory.generatePrivate(keySpec);return privateKey;}}
该步骤总代码:
PublicKey pub; try {pub = RSAwxUtil.getPublicKey(readStream(wxPayAppConfig.getRsaPublicKeyStream())); } catch (Exception e) {e.printStackTrace();baseEntity.setStatus(2);baseEntity.setMessage("读取RSA公钥时异常:"+e.getMessage());return baseEntity; }
加密流程(以卡号为例):
1.直接复制(文档要求)
String rsa ="RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING";
2.调用encrypt()函数,直接贴我的逻辑代码:
byte[] enc_bank_no_byte; try {enc_bank_no_byte = RSAwxUtil.encrypt(bank_card.getBytes(),pub,2048,11,rsa); } catch (Exception e) {e.printStackTrace();baseEntity.setStatus(2);baseEntity.setMessage("对银行卡号进行加密时异常,异常原因:"+e.getMessage());return baseEntity; }String enc_bank_no;//最终银行卡号参数 try {enc_bank_no = BASE64.encode(enc_bank_no_byte); } catch (Exception e) {e.printStackTrace();baseEntity.setStatus(2);baseEntity.setMessage("将银行卡号byte转为字符串时异常,异常原因:"+e.getMessage());return baseEntity; }
——真实姓名:加密过程一致,不赘述。
——银行卡代号:不赘述
——金额:这里要注意,没做过支付的朋友,这个单位是分不是元,用订单金额*100即可。
——签名:上面已经贴了签名工具类,下面会贴我的请求代码。
最终请求代码:
SortedMap<String, String> params = new TreeMap<>(); try{params.put("mch_id",wxPayAppConfig.getMchID());params.put("partner_trade_no",orderNo); // 商户订单号params.put("nonce_str",WXPayUtils.generateUUID());//随机值params.put("enc_bank_no",enc_bank_no);//加密后的银行卡号params.put("enc_true_name",enc_true_name);//加密后的真实姓名params.put("bank_code",bank_code);//银行卡代号params.put("amount",amount);// 标价金额(单位为分)params.put("desc", "提现");//sign签名String sign = WXPayUtils.createSign(params, wxPayAppConfig.getKey());params.put("sign",sign); } catch (Exception e){e.printStackTrace();baseEntity.setStatus(2);baseEntity.setMessage("请求前,封装入参时异常,异常原因:"+e.getMessage());return baseEntity; }
因为入参格式要求xml,请用工具类(上面找)转换:
String payXml; try{payXml = WXPayUtils.mapToXml(params); } catch (Exception e){e.printStackTrace();baseEntity.setStatus(2);baseEntity.setMessage("请求接口前,map转xml异常,异常原因:"+e.getMessage());return baseEntity; }
到此,入参封装好了。
三、请求转账接口
直接调用请求类请求,下面会发,在请求之前,说一说证书路径。如果要将jar部署到云服务器上,可以将你的证书放在云服务器里和项目同一个目录,然后用以下方法直接获取路径:
String path = System.getProperty("user.dir")+"/apiclient_cert.p12";
下面是请求类:
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;import javax.net.ssl.SSLContext;import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;/*** This example demonstrates how to create secure connections with a custom SSL* context.*/
public class ClientCustomSSL {@SuppressWarnings("deprecation")public static String doRefund(String url, String data, String p12_path, String p12_key) throws Exception {KeyStore keyStore = KeyStore.getInstance("PKCS12");FileInputStream instream = new FileInputStream(new File(p12_path));//P12文件目录try {/*** 下载证书时的密码、默认密码是你的MCHID mch_id* */keyStore.load(instream, p12_key.toCharArray());} finally {instream.close();}// Trust own CA and all self-signed certs/*** 下载证书时的密码、默认密码是你的MCHID mch_id* */SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, p12_key.toCharArray())//这里也是写密码的.build();// Allow TLSv1 protocol onlySSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();try {HttpPost httpost = new HttpPost(url); httpost.addHeader("Connection", "keep-alive");httpost.addHeader("Accept", "*/*");httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");httpost.addHeader("Host", "api.mch.weixin.qq.com");httpost.addHeader("X-Requested-With", "XMLHttpRequest");httpost.addHeader("Cache-Control", "max-age=0");httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");httpost.setEntity(new StringEntity(data, "UTF-8"));CloseableHttpResponse response = httpclient.execute(httpost);try {HttpEntity entity = response.getEntity();String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");EntityUtils.consume(entity);return jsonStr;} finally {response.close();}} finally {httpclient.close();}}
}
我的请求代码:(请求类四个参数分别是:付款url,入参xml,证书路径,商户号)
String result; try{result = ClientCustomSSL.doRefund(url, payXml,path,wxPayAppConfig.getMchID()); } catch (Exception e){e.printStackTrace();baseEntity.setStatus(2);baseEntity.setMessage("请求转账接口时异常,异常原因:"+e.getMessage());return baseEntity; }
最后需要将xml转为map:
Map<String, String> payBankMap; try{payBankMap = WXPayUtils.xmlToMap(s); } catch (Exception e){e.printStackTrace();baseEntity.setStatus(2);baseEntity.setMessage("请求结果xml数据转map时异常,异常原因:"+e.getMessage());return baseEntity; }
至此,付款请求完成。
根据payBankMap.get("result_code")参数可以知道付款成功或失败。
最后不要忘记更新相关数据库表的业务逻辑,如:付款后,订单改为已付款之类的。
还有,请保证微信支付运营账户余额大于1.5元,因为每一笔打款订单,微信起步手续费1元。也就是说,就算你打款0.01元,将被扣1.01元。
因为文档没有体现手续费起步1元,我浪费了大半天时间百度,就连技术客服都不知道这个规则,还帮我看后台日志,最后问他同事才知道。这种坑实在是不应该,还有请求时突然不支持的协议(该文档已经屏蔽),从开发社区里看到,两年前的文档漏洞,今天还没改...
另外需要注意的是,每个商户最低打款额不同,有些商户是0.01元,也有看到有很多商户是0.03元。
微信支付:springboot企业付款到个人银行卡相关推荐
- java 微信转账 ca_error_【微信支付】企业付款开发者文档
[微信支付]企业付款开发者文档 2018-11-24 简介 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款 ...
- 微信支付(企业付款到个人微信零钱账户)微信公众平台开发教程(6)
微信支付(企业付款到个人微信零钱账户)微信公众平台开发教程(6 简介 开发步骤 后端代码实现 简介 Senparc.Weixin SDK 是由盛派网络(Senparc)团队自主研发的针对微信各模块的 ...
- PHP之 微信支付 查询企业付款银行卡API 或 查询给企业付款是否到账 功能业务处理
一.情景简述 之前做了微信付款到企业银行卡的功能,但是,给客户打款后,次日才能到账,为及时进行反馈,于是又做了"查询给企业付款是否到账"的功能.这块,我直接写了一个类,进行处理,下 ...
- 微信支付之企业付款(提现,理赔,退款)(java)
/*** 提现操作* @throws Exception */@RequestMapping("doCash")public String doTravelScoreCash(Ht ...
- 微信支付(一) - 企业付款到用户零钱
使用场景介绍 官方说的太绕了, 简单说就是 app运营商(网站/等等)- 代表你,你想给你网站用户打钱: 那么首先你得提交一些列材料去微信申请 申请详细介绍地址参考 https://pay.weixi ...
- 微信支付之企业付款--微信商户后台没有“企业付款到零钱”解决方案
项目需要用到用户提现功能,准备用微信支付提供的企业付款功能,即提供企业向用户付款的功能,支持企业通过API接口付款,或通过微信支付商户平台网页功能操作付款. 登录商户后台准备开通,发现产品中心中并不存 ...
- php 微信支付到银行卡号,【微信支付】企业付款开发者文档
字段名 变量名 必填 类型 说明 返回状态码 return_code 是 String(16) SUCCESS/FAIL 此字段是通信标识,非付款标识,付款是否成功需要查看result_code来判断 ...
- 微信接口 java_【微信支付】企业付款开发者文档
付款方式 ◆ 支持API接口或网页操作,付款至目标用户. 收款用户身份指定 ◆ 通过APPID+OPENID指定收款用户. ◆ APPID需要为申请商户号时的APPID,或者与商户号有绑定关系. ◆ ...
- php 微信证书,【微信支付】企业付款开发者文档
1.签名算法 签名生成的通用步骤如下: 第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=valu ...
最新文章
- 网站开发绝不像你看到的那么简单!
- c++调用python操作mongo
- c++ primer 笔记 (三)
- IDEA 断点调试高级玩法 |debug高手必看!
- python数据结构实验目的_图的基本操作实现(数据结构实验)
- 不要在变量名的旁边加echo和.br;
- 凝思系统改时间_大众改原厂盲点监测系统,中山大众原厂改装,途观L改盲点监测...
- 关注电子商务网站开发-《网站中常用的Jquery插件》
- Kettle增量同步变动数据
- 【UVa11178】Morley's Theorem(向量旋转+直线交点)
- 启用IIS7配置ASP运行环境的详细方法
- 身心灵觉醒视频汇总【建议收藏】
- MSDC 4.3 接口规范(25)
- Win11系统输入法无法调出问题解决方法
- PostGreSQL主从库环境下的从节点故障恢复
- 打印机不打印计算机原因,打印机打印不完整?是这10个原因造成的!打印必备...
- 合成共轭莫比乌斯索烃研究取得进展
- 2020年笔记本电脑计算机专业,适合女生用的笔记本电脑排名2020
- Linux 安装AndroidSdk 并使用zipalign对齐工具完成apk的签名
- 蓝牙协议栈消息的关联