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

微信支付开发h5调用

2015-06-11 16:05 666 查看
这两天做微信支付开发。碰到大坑。纠结死我了。好不容做完。

后台java:直接上代码:注意区分前后端的变量大小写。。。

@RequestMapping(value="/index")
publicModelindex(@RequestParam(value="openid",required=true)Stringopenid,Modelmodel,HttpServletRequestrequest)throwsException{
logger.info("************openid***********为:"+openid);
//获取prepayid
Map<String,String>map=newHashMap<String,String>();
WeiXinConfigwcf=weiXinBaseService.getWeiXinConfig();
StringnonceStr=UUID.randomUUID().toString().substring(0,32);

oauthService.shareFactory(request);
Stringappid=wcf.getAppid();
longtimestamp=System.currentTimeMillis()/1000;
map.put("appid",appid);
map.put("mch_id",WebConfig.get("pay.mch_id"));
map.put("nonce_str",nonceStr);
map.put("body",WebConfig.get("pay.body"));
map.put("out_trade_no",payWxUtil.orderNum());
map.put("total_fee",WebConfig.get("pay.price"));
map.put("spbill_create_ip",request.getRemoteAddr());
map.put("notify_url",WebConfig.get("hostAddress")+request.getContextPath()+"/babyShow/payInfo/info");
map.put("trade_type","JSAPI");
map.put("openid",openid);
StringpaySign=SignUtil.getPayCustomSign(map,WebConfig.get("pay.key"));
map.put("sign",paySign);
Stringxml=CommonUtil.ArrayToXml(map);
Stringprepayid=payWxUtil.getPrepayid(xml);
logger.info("prepareid*****************************="+prepayid);
//封装h5页面调用参数
Map<String,String>signMap=newHashMap<String,String>();
signMap.put("appId",appid);
logger.info("appId="+appid);
signMap.put("timeStamp",timestamp+"");
logger.info("timeStamp="+timestamp);
signMap.put("package","prepay_id="+prepayid);
logger.info("package="+"prepay_id="+prepayid);
signMap.put("signType","MD5");
logger.info("singType="+"MD5");
signMap.put("nonceStr",nonceStr);
logger.info("nonceStr="+nonceStr);
model.addAttribute("paytimestamp",timestamp);
model.addAttribute("paypackage","prepay_id="+prepayid);
model.addAttribute("paynonceStr",nonceStr);
model.addAttribute("paysignType","MD5");
StringpaySign2=SignUtil.getPayCustomSign(signMap,WebConfig.get("pay.key"));
model.addAttribute("paySign",paySign2);
logger.info("paySign="+paySign2);
returnmodel;

}


以上代码获取openid需要根据网页授权来获取。这里就不多讲了。主要讲讲获取prepayid和生成h5页面所需参数,

这里面比较麻烦的就是签名的获取

查看方法SignUtil.getPayCustomSign(signMap,WebConfig.get("pay.key"))

代码如下

/**
*获取支付所需签名
*@paramticket
*@paramtimeStamp
*@paramcard_id
*@paramcode
*@return
*@throwsException
*/
publicstaticStringgetPayCustomSign(Map<String,String>bizObj,Stringkey)throwsException{

StringbizString=CommonUtil.FormatBizQueryParaMap(bizObj,
false);
logger.info(bizString);
returnMD5SignUtil.sign(bizString,key);
}


其中CommonUtil.FormatBizQueryParaMap是用来做字典排序的。有参考了网上的例子。就没单独做。

publicstaticStringFormatBizQueryParaMap(Map<String,String>paraMap,
booleanurlencode)throwsException{

Stringbuff="";
try{
List<Map.Entry<String,String>>infoIds=newArrayList<Map.Entry<String,String>>(
paraMap.entrySet());

Collections.sort(infoIds,
newComparator<Map.Entry<String,String>>(){
publicintcompare(Map.Entry<String,String>o1,
Map.Entry<String,String>o2){
return(o1.getKey()).toString().compareTo(
o2.getKey());
}
});

for(inti=0;i<infoIds.size();i++){
Map.Entry<String,String>item=infoIds.get(i);
//System.out.println(item.getKey());
if(item.getKey()!=""){

Stringkey=item.getKey();
Stringval=item.getValue();
if(urlencode){
val=URLEncoder.encode(val,"utf-8");

}
buff+=key+"="+val+"&";

}
}

if(buff.isEmpty()==false){
buff=buff.substring(0,buff.length()-1);
}
}catch(Exceptione){
thrownewException(e.getMessage());
}
returnbuff;
}


其中MD5SignUtil.sign(bizString,key)方法如下

publicstaticStringsign(Stringcontent,Stringkey)
throwsException{
StringsignStr="";
signStr=content+"&key="+key;

returnMD5Util.MD5(signStr).toUpperCase();

}


其中MD5Util.MD5(signStr)方法如下


publicfinalstaticStringMD5(Strings){
charhexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
try{
byte[]btInput=s.getBytes();
MessageDigestmdInst=MessageDigest.getInstance("MD5");
mdInst.update(btInput);
byte[]md=mdInst.digest();
intj=md.length;
charstr[]=newchar[j*2];
intk=0;
for(inti=0;i<j;i++){
bytebyte0=md[i];
str[k++]=hexDigits[byte0>>>4&0xf];
str[k++]=hexDigits[byte0&0xf];
}
returnnewString(str);
}catch(Exceptione){
e.printStackTrace();
returnnull;
}
}


CommonUtil.ArrayToXml(map)方法如下


publicstaticStringArrayToXml(Map<String,String>arr){
Stringxml="<xml>";

Iterator<Entry<String,String>>iter=arr.entrySet().iterator();
while(iter.hasNext()){
Entry<String,String>entry=iter.next();
Stringkey=entry.getKey();
Stringval=entry.getValue();
if(IsNumeric(val)){
xml+="<"+key+">"+val+"</"+key+">";

}else
xml+="<"+key+"><![CDATA["+val+"]]></"+key+">";
}

xml+="</xml>";
returnxml;
}


publicstaticbooleanIsNumeric(Stringstr){
if(str.matches("\\d*")){
returntrue;
}else{
returnfalse;
}
}






发送请求到微信获取prepayid代码如下

publicstaticStringURL="https://api.mch.weixin.qq.com/pay/unifiedorder";
@SuppressWarnings("deprecation")
publicJSONObjectgetPrepayJson(Stringxml){
HttpClienthttpClient=newHttpClient(newHttpClientParams(),newSimpleHttpConnectionManager(true));
InputStreamis=null;
PostMethodmethod=null;
try{
Stringurl=URL;
method=HttpClientUtils.postMethod(url);
method.setRequestBody(xml);
httpClient.executeMethod(method);
//读取响应
is=method.getResponseBodyAsStream();
JSONObjecto=Xml2JsonUtil.xml2JSON(is);
returno;
}catch(Exceptione){
e.printStackTrace();
}finally{
if(method!=null){
method.releaseConnection();
}
if(is!=null){
try{
is.close();
}catch(IOExceptione1){
e1.printStackTrace();
}
}
}
returnnull;
}
publicStringgetPrepayid(Stringxml){
try{
JSONObjectjo=getPrepayJson(xml);
JSONObjectelement=jo.getJSONObject("xml");
Stringprepayid=((JSONArray)element.get("prepay_id")).get(0).toString();
returnprepayid;
}catch(Exceptione){
e.printStackTrace();
}
returnnull;
}
publicStringorderNum(){
Stringchars="0123456789";
Stringorder=System.currentTimeMillis()+"";
Stringres="";
for(inti=0;i<19;i++){
Randomrd=newRandom();
res+=chars.charAt(rd.nextInt(chars.length()-1));
}
order+=res;
returnorder;
}


xml转json方法Xml2JsonUtil.xml2JSON(is);。摘自网络

/**
*转换一个xml格式的字符串到json格式
*
*@paramxml
*xml格式的字符串
*@return成功返回json格式的字符串;失败反回null
*/
@SuppressWarnings("unchecked")
publicstaticJSONObjectxml2JSON(InputStreamis){
JSONObjectobj=newJSONObject();
try{
SAXReadersb=newSAXReader();
Documentdoc=sb.read(is);
Elementroot=doc.getRootElement();
obj.put(root.getName(),iterateElement(root));
returnobj;
}catch(Exceptione){
log.error("传入XML后转换JSON出现错误=====Xml2JsonUtil-->xml2JSON============>>",e);
returnnull;
}
}

/**
*一个迭代方法
*
*@paramelement
*:org.jdom.Element
*@returnjava.util.Map实例
*/
@SuppressWarnings("unchecked")
privatestaticMapiterateElement(Elementelement){
Listjiedian=element.elements();
Elementet=null;
Mapobj=newHashMap();
Listlist=null;
for(inti=0;i<jiedian.size();i++){
list=newLinkedList();
et=(Element)jiedian.get(i);
if(et.getTextTrim().equals("")){
if(et.elements().size()==0)
continue;
if(obj.containsKey(et.getName())){
list=(List)obj.get(et.getName());
}
list.add(iterateElement(et));
obj.put(et.getName(),list);
}else{
if(obj.containsKey(et.getName())){
list=(List)obj.get(et.getName());
}
list.add(et.getTextTrim());
obj.put(et.getName(),list);
}
}
returnobj;
}




服务端基本这么多

前端被微信和我自己挖了大坑,整整搞了两天,擦

先是看的微信文档jssdk文档(开始埋坑。。)

页面引入js

加入

wx.config({
debug:false,//开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId:'${appid}',//必填,公众号的唯一标识
timestamp:'${timestamp}',//必填,生成签名的时间戳
nonceStr:'${nonceStr}',//必填,生成签名的随机串
signature:'${signature}',//必填,签名,见附录1
jsApiList:[
'chooseWXPay'
]//必填,需要使用的JS接口列表,所有JS接口列表见附录2

});


嗯。配置好了。如果传入jsconfig的参数。。。

然后看到jssdk里面有发送一个微信支付请求?

嗯加进去



functionpay(){
wx.chooseWXPay({
timestamp:${paytimestamp},//支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr:'${paynonceStr}',//支付签名随机串,不长于32位
package:'${paypackage}',//统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType:'${paysignType}',//签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign:'${paySign}',//支付签名
success:function(res){
alert("支付成功");
//支付成功后的回调函数
}
});
}






然后发布,执行调试。。尼玛。怎么样都支付不了。一会儿报订单信息错误、一会儿报签名错误。。。找了N多资料均不对

后来想啊。大不了用商户平台提供的文档写接口什么的。于是加入了代码

functiononBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest',{
"appId":"${appid}",//公众号名称,由商户传入
"timeStamp":"${paytimestamp}",//时间戳,自1970年以来的秒数
"nonceStr":"${paynonceStr}",//随机串
"package":"${paypackage}",
"signType":"${paysignType}",//微信签名方式:
"paySign":"${paySign}"//微信签名
},
function(res){
alert(res.err_msg);//使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返

}
);
}
functionpay2(){
if(typeofWeixinJSBridge=="undefined"){
if(document.addEventListener){
document.addEventListener('WeixinJSBridgeReady',onBridgeReady,false);
}elseif(document.attachEvent){
document.attachEvent('WeixinJSBridgeReady',onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady',onBridgeReady);
}
}else{
onBridgeReady();
}
}


发布调试。。。还是不对。。两个按钮pay()和pay2()均不对。pay方法还是一会儿订单信息错误一会儿签名错误。pay2()方法则一直报签名错误。。。尼玛。吧经历放后台签名。。怎么改都不行。签名明明对的啊。可以获取prepayid的。为毛封装h5参数时就出错了呢。。。折腾啊。。。搞了N久。。就尼玛不对。。。后来一个小错误pay方法js报错了。。结果pay2方法确可以执行了。。。吧pay的js报错去了之后pay2又不能用了。。我擦。。哥有预感。。难道两种方式冲突了??于是我把config和pay方法删除了再试试。。。尼玛果然可以了。不能加入config和pay。。。果然可以了。。。我擦。折腾的。。微信啃爹啊。第一种方式无法用有没有,误导人啊。。。正确结果就是商品平台的文档使用方法js如下:

functiononBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest',{
"appId":"${appid}",//公众号名称,由商户传入
"timeStamp":"${paytimestamp}",//时间戳,自1970年以来的秒数
"nonceStr":"${paynonceStr}",//随机串
"package":"${paypackage}",
"signType":"${paysignType}",//微信签名方式:
"paySign":"${paySign}"//微信签名
},
function(res){
alert(res.err_msg);//使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返

}
);
}
functionpay(){
if(typeofWeixinJSBridge=="undefined"){
if(document.addEventListener){
document.addEventListener('WeixinJSBridgeReady',onBridgeReady,false);
}elseif(document.attachEvent){
document.attachEvent('WeixinJSBridgeReady',onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady',onBridgeReady);
}
}else{
onBridgeReady();
}
}


至此。终于把微信支付搞定了。留着博客。防止后人走弯路(config里面不能加入chooseWXPay方法。。切记)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: