微信APP支付Java服务端,爬出一半坑,记录下心得。
同样,对于微信APP支付申请和配置在这里就不做说明了,拿到APPID和partnerid,在商户平台设置好自己的key之后再说。
微信对比支付宝而言,确实比较坑,官方文档不清晰,稍不留神就掉坑里了,而且没有客服,和客户端的小伙伴试了好多次终于在今天调起微信支付,再次在此记录下微信支付服务端的心得,给后面需要用的小伙伴做下参考,共同学习。。
首先,因为官方没有给出服务端的demo,所以我也是在网上找别人的demo 看着,然后自己调试,和微信交互就不细说了,我参考的是这个大神的demo ,把其中的appid等等参数更换成自己申请的ID 然后调用执行之后拿到这个结果 http://blog.csdn.net/seven_cm/article/details/41559301
这里的流程是:后台生成订单之后,把参数信息打包签名,通过post发送给微信,微信返回xml格式的数据,返回的数据里边有个很重要的prepayid—预支付交易会话ID。这个数据需要传递给前端 所以我们需要解析这个微信传过来的xml数据
生成签名规则:
/**
* 微信支付签名算法sign
* @param characterEncoding
* @param parameters
* @return
*/
@SuppressWarnings("rawtypes")
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=" + Key);
System.out.println("字符串拼接后是:"+sb.toString());
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
第一次签名,即订单内容
//参数:开始生成签名
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("nonce_str", nonce_str);
parameters.put("detail", detail);
parameters.put("attach", attach);
parameters.put("out_trade_no", out_trade_no);
parameters.put("total_fee", total_fee);
parameters.put("time_start", time_start);
parameters.put("time_expire", time_expire);
parameters.put("notify_url", notify_url);
parameters.put("trade_type", trade_type);
parameters.put("spbill_create_ip", spbill_create_ip);
String sign = WXSignUtils.createSign("UTF-8", parameters);
System.out.println("签名是:"+sign);
生成的xml参数,解析prepayid
//构造xml参数
String xmlInfo = HttpXmlUtils.xmlInfo(unifiedorder);
String wxUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
String method = "POST";
String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString();
System.out.println(weixinPost);
ParseXMLUtils.jdomParseXml(weixinPost);//解析key值
到这里准备工作就完成了,然后我们需要把参数传递给客户端
客户端需要的参数,官方文档是这样说的:
这里的
appid 就是我们微信支付申请的ID
partnerid 就是申请的商户平台的账号
prepayid 预支付ID 就是上面说的解析xml数据之后拿到的值
package 官方说,暂填写固定值Sign=WXPay
noncestr 随机生成的16为字符串
timestamp 注意:这里是个巨坑,这里的时间戳指的是1970年到发起支付的秒数,并且是十位,,Calendar.getInstance().getTimeInMillis()这个获取的是13位,正确的是:Calendar.getInstance().getTimeInMillis()/1000 拿到十位秒数
sign 返回给客户端的二次签名,巨巨坑,下面细说:
服务端一共需要两次签名,第一次生成签名是返回给微信服务端,签名的内容是订单信息,参考上面大神demo
第二次的签名,即服务端返回给客户端的签名,方法与第一次签名相同,签名的内容就是上面的六位参数外加商户平台申请的key
拿到签名之后,把以上参数和签名通过json返回给客户端就OK了,剩下的就是客户端解析json数据调起微信支付。
服务端把数据传递正确之后前端很快就可以调起支付,主要是微信官方文档说的太简略,我也是和前端小伙伴一次一次调整数据试出来,微信只要不正确就只报-1非常无奈,这样比起来支付宝开发文档简直太好了。