赞
踩
第一次做这个功能,坑有点多(官方坑也有),最终完全了付款到银行卡功能,一一为大家踩坑。文章只讲解关于转账至银行卡的业务逻辑,需要用到的工具类,还有具体做法都会贴,适合第一次开发此功能的人看。
官方文档:
一、准备
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 ERROR
- System.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 only
- SSLConnectionSocketFactory 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元。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。