您的位置:首页 > 移动开发 > 微信开发

Java微信支付总结(一):获得prepay_id(以及生成微信支付签名)

2017-02-16 11:57 381 查看
默认你已经取得了微信支付相关的权限,并且有了商户号,key值等等。

如果你一直签名错误,请看上一篇帖子:http://blog.csdn.net/qq_25821067/article/details/55253399

要想获取prepay_id,就必须要生成正确的签名,一下是微信官方文档说明https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3:


1、

签名算法------(签名校验工具)

签名生成的通用步骤如下:

第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特别注意以下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段

第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。

key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置

举例:

假设传送的参数如下:

appid: wxd930ea5d5a258f4f

mch_id: 10000100

device_info: 1000

body: test

nonce_str: ibuaiVcKdpRxkhJA

第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:

stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";

第二步:拼接API密钥:

stringSignTemp="stringA&key=192006250b4c09247ec02edce69f6a2d"

sign=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7"

最终得到最终发送的数据:

<xml>

<appid>wxd930ea5d5a258f4f</appid>

<mch_id>10000100</mch_id>

<device_info>1000<device_info>

<body>test</body>

<nonce_str>ibuaiVcKdpRxkhJA</nonce_str>

<sign>9A0A8659F005D6984697E2CA0A9CF3B7</sign>

<xml>

最开始的时候,第一次弄的话,先去微信支付接口调试出去输入参数调试,微信支付接口调试网址:https://pay.weixin.qq.com/wiki/tools/signverify/。
选择设定需要的参数后点击生成签名,最下面就会出现一个xml格式的字符串。然后利用post方法提交到https://api.mch.weixin.qq.com/pay/unifiedorder。我是Java,我的方法就是把调试接口那个拼凑出一个xml格式的String字符串,然后提交。

我用到了httpclient 4.5.3这个框架。

核心的post代码如下:

System.out.println("最终提交xml:"+xml);
post.setEntity(new StringEntity(xml,"UTF-8"));
HttpResponse execute = httpClient.execute(post);
HttpEntity entity = execute.getEntity();
String responseContent = EntityUtils.toString(entity,"utf-8");
System.out.println("PayController index获取到的总数据:"+responseContent); 上面那个xml变量,就是上面说的微信官方接口测试生成的xml格式的字符串,自己拼凑成串就行了。
post.setEntity(new StringEntity(xml,"UTF-8"));这一行特别重要,我之前就是少写了UTF-8这个参数,结果一直报签名错误。

然后返回内容大概如下:

<xml>
   <return_code><![CDATA[SUCCESS]]></return_code>
   <return_msg><![CDATA[OK]]></return_msg>
   <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
   <mch_id><![CDATA[10000100]]></mch_id>
   <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
   <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
   <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
   <result_code><![CDATA[SUCCESS]]></result_code>
   <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
   <trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

就表明OK了。你从微信测试官方生成的提交的xml串一般是不回出现问题的,如果出现签名错误,那估计就是我上一篇说的那个问题了。

如果获得了正确的返回,那就是没问题了,里面最重要的就是那个prepay_id。也是我们需要它的地方。

当然上面我们只是用了微信测试接口生成了sign签名。下面马上说生成签名的方法。

/**
* 微信支付签名算法sign
* @param characterEncoding
* @param parameters
* @return
*/
@Test
public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
Object v = entry.getValue();
if(null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}

sb.append("key=" + WeChatPayUtils.key);
System.out.println("字符串:"+sb.toString());
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
} MD5Util工具类代码如下:
package cn.cqzdkj.utils;

import java.security.MessageDigest;

public class MD5Util {
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));

return resultSb.toString();
}

private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}

public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString
.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString
.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString;
}

private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}
然后在需要的地方直接调用上面的ctreasign这个方法就行了。
SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
parameters.put("appid", appid);
parameters.put("mch_id", mch_id);
parameters.put("nonce_str",nonce_str);
parameters.put("body", body);
parameters.put("out_trade_no", "20170215");
parameters.put("total_fee", 1);
parameters.put("spbill_create_ip", "x.x.x.x");
parameters.put("notify_url","http://xxxxx.com");
parameters.put("trade_type", "JSAPI");
parameters.put("openid", "oGY_ZvxxxxxM");
parameters.put("sign","");

String characterEncoding = "UTF-8";
String mySign = createSign(characterEncoding,parameters);
System.out.println("我 的签名是:"+mySign);

到上面就是生成签名的方法。如果还有不懂的就留言评论吧,我这两天也是走了很多坑。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  微信签名 prepay_id
相关文章推荐