微信小程序> 微信公众号红包,Java微信支付开发|公众号发红包、企业付款、微信网页支付、微信小程序支付附源码!!!

微信公众号红包,Java微信支付开发|公众号发红包、企业付款、微信网页支付、微信小程序支付附源码!!!

浏览量:931 时间: 来源:男儿何必尽成功
本文主要介绍Java微信公众号、微信小程序支付和提现相关的开发流程。请注意,支付是用户向微信商户付款,提现是微信商户向用户付款或者发送红包。
阅读本文前需掌握微信公众平台开发、微信小程序开发、微信支付等相关基础知识。
一、公众号提现公众号中提现有2种形式,第一种是企业付款,另一种是发送红包。下面对这两种形式分别介绍。
1.1公众号企业付款企业付款为企业提供付款至用户零钱的能力,支持通过API接口付款,或通过微信支付商户平台(pay.weixin.qq.com)网页操作付款。我们要介绍的肯定是API接口付款。
1.1.1准备工作准备一个服务号或订阅号(不确定是否需要开通微信认证);准备一个微信商户,该商户需开通企业付款产品权限;微信商户需要与公众号绑定。1.1.2开发企业付款微信API地址:
废话不多说,直接上源码(包含注释,一目了然):
/企业付款@parampublicAccountOpenId用户相对于公众号的openId@parammoney付款金额单位是分/publicstaticMapString,ObjectEnterprisePayment(StringpublicAccountOpenId,intmoney){MapString,ObjectresultMap=newHashMap();Stringu=getUUID();//这里是通过生成一个32位的UUID保证商户订单号不重复JSONObjectjsonObj=newJSONObject();jsonObj.put("mch_appid",SystemContant.PUBLIC_ACCOUNT_APPID);//公众号appIdjsonObj.put("mchid",SystemContant.MCH_ID);//商户号jsonObj.put("nonce_str",u);//随机数jsonObj.put("partner_trade_no",u);//商户订单号这里为了方便,随机数和商户订单号采用相同的值jsonObj.put("openid",publicAccountOpenId);//用户相对于公众号的openIdjsonObj.put("check_name","NO_CHECK");//是否校验用户姓名如果校验,re_user_name参数需填写用户真实姓名jsonObj.put("amount",money);//付款金额jsonObj.put("desc","奖励提现");//企业付款备注jsonObj.put("spbill_create_ip",SystemContant.SERVER_IP);//Ip地址该IP同在商户平台设置的IP白名单中的IP没有关联,该IP可传用户端或者服务端的IPtry{jsonObj.put("sign",paramSort(jsonObj));//根据微信参数排序及加密规则生成签名}catch(Exceptione){log.error("--提现参数排序失败---CauseBy:"+e.getMessage()+"--publicAccountOpenId:"+publicAccountOpenId+"--money:"+money);resultMap.put("flag",false);resultMap.put("msg","系统内部错误");resultMap.put("errCodeDes","提现参数排序失败");returnresultMap;}StringxmlStr=ssl(SystemContant.DRAW_CASH_WECHAT_URL,jsonToXML(jsonObj));//post方式携带证书调用微信接口try{JSONObjectjsonObjResult=xmltoJson(xmlStr);//将微信返回的xml转化成jsonJSONObjectjsonObjXML=jsonObjResult.getJSONObject("xml");StringreturnCode=jsonObjXML.getString("return_code");//通信标识if(StringUtils.equals("FAIL",returnCode)){//通信失败或签名错误log.error("调用微信支付通信失败---"+"--xmlStr:"+xmlStr+"--publicAccountOpenId:"+publicAccountOpenId+"--money:"+money);resultMap.put("flag",false);resultMap.put("msg","系统内部错误");resultMap.put("errCodeDes","调用微信支付通信失败");returnresultMap;}StringresultCode=jsonObjXML.getString("result_code");if(StringUtils.equals("FAIL",resultCode)){//状态未明确//resultCode返回值SUCCESS/FAIL,注意:当状态为FAIL时,存在业务结果未明确的情况。如果如果状态为FAIL,请务必关注错误代码(err_code字段),通过查询查询接口确认此次付款的结果。StringerrCodeDes=jsonObjXML.getString("err_code_des");//失败原因//errCode为错误码信息,注意:出现未明确的错误码时(SYSTEMERROR等),请务必用原商户订单号重试,或通过查询接口确认此次付款的结果。StringerrCode=jsonObjXML.getString("err_code");//失败状态码resultMap.put("flag",false);resultMap.put("errCode",errCode);resultMap.put("errCodeDes",errCodeDes);resultMap.put("msg","付款失败。后台人工处理中,请您耐心等候");returnresultMap;}else{//付款成功resultMap.put("flag",true);resultMap.put("partner_trade_no",jsonObjXML.getString("partner_trade_no"));//商户订单号resultMap.put("payment_no",jsonObjXML.getString("payment_no"));//微信付款订单号resultMap.put("msg","提现成功");returnresultMap;}}catch(Exceptione){log.error("微信支付解析微信返回xml失败---CauseBy:"+e.getMessage()+"--xmlStr:"+xmlStr+"--publicAccountOpenId:"+publicAccountOpenId+"--money:"+money);resultMap.put("flag",false);resultMap.put("errCodeDes","微信支付解析微信返回xml失败");resultMap.put("msg","系统内部错误");returnresultMap;}}/按照微信API规则对参数排序并拼装字符串,最后对字符串MD5加密@authorfangw@paramjsonObj@return@throwsUnsupportedEncodingException@throwsNoSuchAlgorithmException/publicstaticStringparamSort(JSONObjectjsonObj)throwsNoSuchAlgorithmException,UnsupportedEncodingException{//声明一个数组,用于存放参数String[]arr=newString[jsonObj.keySet().size()];//将map中的参数存到数组中intnum=0;for(Objecto:jsonObj.keySet()){arr[num]=String.valueOf(o);num++;}//排序(冒泡排序)for(inti=0;iarr.length-1;i++){//外层循环控制排序趟数for(intj=0;jarr.length-1-i;j++){//内层循环控制每一趟排序多少次if(arr[j].compareTo(arr[j+1])0){Stringtemp=arr[j];arr[j]=arr[j+1];arr[j+1]=temp;}}}//拼装字符串StringBuffersb=newStringBuffer();for(Strings:arr){sb.append(s).append("=").append(jsonObj.get(s)).append("&");}Stringstr=sb.append("key=").append(SystemContant.WECHAT_PAY_API_SECRET).toString();Stringsign=getMD5(str).toUpperCase();returnsign;}/生成MD5@paramstr@return/publicstaticStringgetMD5(Stringstr){try{//生成一个MD5加密计算摘要MessageDigestmd=MessageDigest.getInstance("MD5");//计算md5函数md.update(str.getBytes());//digest()最后确定返回md5hash值,返回值为8为字符串。因为md5hash值是16位的hex值,实际上就是8位的字符//BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值Stringmd5=newBigInteger(1,md.digest()).toString(16);//BigInteger会把0省略掉,需补全至32位returnfillMD5(md5);}catch(Exceptione){thrownewRuntimeException("MD5加密错误:"+e.getMessage(),e);}}/填充MD5值@parammd5@return/publicstaticStringfillMD5(Stringmd5){returnmd5.length()==32?md5:fillMD5("0"+md5);}/post请求微信接口,同时携带商户证书。需提前在商户平台上下载证书并存放到指定位置@paramurl微信企业付款接口urlhttps://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers@paramdata请求接口携带的参数@return/publicstaticStringssl(Stringurl,Stringdata){StringBuffermessage=newStringBuffer();try{KeyStorekeyStore=KeyStore.getInstance("PKCS12");FileInputStreaminstream=newFileInputStream(newFile("/usr/local/cert/apiclient_cert.p12"));keyStore.load(instream,SystemContant.MCH_ID.toCharArray());SSLContextsslcontext=SSLContexts.custom().loadKeyMaterial(keyStore,SystemContant.MCH_ID.toCharArray()).build();SSLConnectionSocketFactorysslsf=newSSLConnectionSocketFactory(sslcontext,newString[]{"TLSv1"},null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);CloseableHttpClienthttpclient=HttpClients.custom().setSSLSocketFactory(sslsf).build();HttpPosthttpost=newHttpPost(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;MSIE8.0;WindowsNT6.0)");httpost.setEntity(newStringEntity(data,"UTF-8"));CloseableHttpResponseresponse=httpclient.execute(httpost);try{HttpEntityentity=response.getEntity();if(entity!=null){BufferedReaderbufferedReader=newBufferedReader(newInputStreamReader(entity.getContent(),"UTF-8"));Stringtext;while((text=bufferedReader.readLine())!=null){message.append(text);}}EntityUtils.consume(entity);}catch(IOExceptione){e.printStackTrace();}finally{response.close();}}catch(Exceptione1){e1.printStackTrace();}returnmessage.toString();}/将json数据转化成XML字符串@paramjson@return/publicstaticStringjsonToXML(JSONObjectjson){XMLSerializerxmlSerializer=newXMLSerializer();//根节点名称xmlSerializer.setRootName("xml");//不对类型进行设置xmlSerializer.setTypeHintsEnabled(false);StringxmlStr="";xmlStr=xmlSerializer.write(json);returnxmlStr;}主要依赖包如下:
importjavax.net.ssl.SSLContext;importjava.io.File;importjava.io.FileInputStream;importjava.math.BigInteger;importjava.security.KeyStore;importorg.apache.http.conn.ssl.SSLContexts;importorg.apache.http.client.methods.CloseableHttpResponse;importorg.apache.http.client.methods.HttpPost;importorg.apache.http.conn.ssl.SSLConnectionSocketFactory;importorg.apache.http.impl.client.CloseableHttpClient;importorg.apache.http.HttpEntity;importnet.sf.json.JSONObject;importnet.sf.json.xml.XMLSerializer;importjava.security.MessageDigest;importjava.util.HashMap;importjava.util.Map;1.1.3注意点需要根据微信参数排序、加密规则生成签名,并将签名放到post请求数据中;post方式请求微信企业付款接口时需携带证书,post请求数据需为xml字符串;微信返回的result_code为FAIL时并不能说明付款失败,需要采用原商户订单号重试或调用接口查询付款结果。1.1.4效果图
1.2公众号发放现金红包商户可以向微信支付用户发放现金红包。用户领取红包后,资金到达用户微信支付零钱账户,和零钱包的其他资金有一样的使用出口;若用户未领取,资金将会在24小时后退回商户的微信支付账户中。
1.2.1准备工作准备一个服务号或订阅号(不确定是否需要开通微信认证);准备一个微信商户,该商户需开通现金红包产品权限;微信商户需要与公众号绑定。1.2.2开发公众号发放现金红包API地址:
还是直接上源码和注释:
/企业发送红包@parampublicAccountOpenId用户公众号openId@parammoney红包金额单位是分@paramwishStr红包祝福语/publicstaticMapString,ObjectEnterpriseRedBag(StringpublicAccountOpenId,intmoney,StringwishStr){MapString,ObjectresultMap=newHashMap();Stringu=getUUID();//生成一个32位的UUID用于随机数和商户订单号JSONObjectjsonObj=newJSONObject();jsonObj.put("wxappid",SystemContant.PUBLIC_ACCOUNT_APPID);//公众号appIdjsonObj.put("mch_id",SystemContant.MCH_ID);//商户IDjsonObj.put("nonce_str",u);//随机字符串jsonObj.put("mch_billno",System.currentTimeMillis()+u.substring(0,12));//商户订单号jsonObj.put("send_name","购即省");//红包发送者名称jsonObj.put("re_openid",publicAccountOpenId);//接受红包的用户openid,为用户在wxappid下的唯一标识jsonObj.put("total_amount",money);//红包金额jsonObj.put("total_num",1);//红包发放总人数jsonObj.put("wishing",wishStr);//红包祝福语jsonObj.put("remark","购物即省钱");//备注信息jsonObj.put("act_name","奖励提现");//活动名称jsonObj.put("client_ip",SystemContant.SERVER_IP);//调用接口的机器Ip地址jsonObj.put("scene_id","PRODUCT_2");//发放红包使用场景,红包金额大于200或者小于1元时必传try{jsonObj.put("sign",paramSort(jsonObj));//根据微信参数排序及加密规则生成签名}catch(Exceptione){log.error("--提现参数排序失败---CauseBy:"+e.getMessage()+"--publicAccountOpenId:"+publicAccountOpenId+"--money:"+money);resultMap.put("flag",false);resultMap.put("msg","系统内部错误");resultMap.put("errCodeDes","提现参数排序失败");returnresultMap;}StringxmlStr=ssl(SystemContant.WECHAT_SEND_REDBAG_URL,jsonToXML(jsonObj));//post方式携带证书调用微信接口try{JSONObjectjsonObjResult=xmltoJson(xmlStr);//将微信返回的xml转化成jsonJSONObjectjsonObjXML=jsonObjResult.getJSONObject("xml");StringreturnCode=jsonObjXML.getString("return_code");//通信标识if(StringUtils.equals("FAIL",returnCode)){//通信失败或签名错误log.error("调用微信支付通信失败---"+"--xmlStr:"+xmlStr+"--publicAccountOpenId:"+publicAccountOpenId+"--money:"+money);resultMap.put("flag",false);resultMap.put("msg","系统内部错误");resultMap.put("errCodeDes","调用微信支付通信失败");returnresultMap;}StringresultCode=jsonObjXML.getString("result_code");//业务结果if(StringUtils.equals("FAIL",resultCode)){//状态未明确//请求查询接口确认状态信息//resultCode返回值SUCCESS/FAIL,注意:当状态为FAIL时,存在业务结果未明确的情况。如果如果状态为FAIL,请务必关注错误代码(err_code字段),通过查询查询接口确认此次付款的结果。StringerrCodeDes=jsonObjXML.getString("err_code_des");//失败原因StringerrCode=jsonObjXML.getString("err_code");//失败状态码resultMap.put("flag",false);resultMap.put("errCode",errCode);resultMap.put("errCodeDes",errCodeDes);resultMap.put("msg","提现失败。后台人工处理中,请您耐心等候");returnresultMap;}else{//付款成功resultMap.put("flag",true);resultMap.put("partner_trade_no",jsonObjXML.getString("mch_billno"));//商户订单号resultMap.put("payment_no",jsonObjXML.getString("send_listid"));//红包订单的微信单号resultMap.put("msg","提现成功");returnresultMap;}}catch(Exceptione){log.error("微信支付解析微信返回xml失败---CauseBy:"+e.getMessage()+"--xmlStr:"+xmlStr+"--publicAccountOpenId:"+publicAccountOpenId+"--money:"+money);resultMap.put("flag",false);resultMap.put("errCodeDes","微信支付解析微信返回xml失败");resultMap.put("msg","系统内部错误");returnresultMap;}}内部用到的方法及相关jar依赖已在上文给出。
1.2.3注意点需要根据微信参数排序、加密规则生成签名,并将签名放到post请求数据中;post方式请求微信企业付款接口时需携带证书,post请求数据需为xml字符串;微信返回的result_code为FAIL时并不能说明付款失败,需要采用原商户订单号重试或调用接口查询付款结果;如果需要发送小于1元或大于200元的红包需要在微信商户上申请开通,否则调用接口不成功;现金红包发放后会以公众号消息的形式触达用户,不同情况下触达消息的形式会有差别,与用户关注公众号时长有关。1.2.4效果图
二、小程序提现小程序提现目前也是有2种形式,第一种形式是企业付款,第二种是发送现金红包。这里要注意,商家并不能直接向小程序用户发送红包,用户只有关注了绑定小程序的公众号才能以公众号的形式发送给用户现金红包。
2.1小程序企业付款小程序企业付款和公众号企业付款的开发代码是一样的,只是需要把mch_appid、openid等参数替换为小程序的对应参数值。代码这里不再赘述。
2.1.1准备工作准备一个微信小程序;准备一个微信商户,该商户需开通企业付款产品权限;微信商户需要与小程序绑定。2.1.2效果图效果图和公众号企业付款效果图一致。
2.2小程序发送红包目前不支持商户向小程序用户直接发送红包,如果需要实现小程序发送红包的效果,那么可以有2种方式。
第一种是通过小程序前端效果图的方式来呈现。当用户在小程序中点击提现时,在小程序前端弹框实现一个“拆红包”的效果,当用户点击“拆”的时候,后台接口以企业付款的形式直接付款至用户零钱。这种方式效果极好。
第二种是通过公众号发送现金红包。这种方式需要开发者将小程序和公众号都绑定到微信开放平台,用于获取unionId。笔者所做的小程序因为需要向公众号引流,所以采用的是这种方式。首先我们在mysql中建一张表,表结构如下:

当小程序用户第一次访问小程序时,弹框获取授权,用于获取用户敏感信息:
buttonopen-type="getUserInfo"lang="zh_CN"bindgetuserinfo="onGotUserInfo"确定/button

用户点击确定之后在onGotUserInfo方法中对微信返回的敏感数据encryptedData进行解密,获取到unionId,进而将小程序openId和unionId保存到数据库中。当用户在小程序中点击提现时,因为表中的公众号openId不存在,所以需要提醒用户关注对应的公众号。在用户关注公众号时,通过用户的openId和公众号ACCESS_TOKEN作为参数,调用微信接口,可以获取到unionId。因为公众号和小程序都绑定到了微信开放平台上,所以它们的用户unionId是相同的。这样,就可以找到小程序和公众号两者的openId对应关系,小程序中点击提现的时候,可以将红包以公众号的形式发送给用户。
三、微信网页支付微信网页支付在微信官方API中被称作微信JSAPI支付,应用场景如下:
商户已有H5商城网站,用户通过点击链接、点击公众号菜单或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买。
注:微信JSAPI支付是在微信浏览器内完成支付。如果是外部浏览器,那需要对接微信H5支付。
微信JSAPI支付官方文档:
3.1准备工作1、准备一个已通过微信认证的公众号,同时保证该公众号有“微信支付”的权限
2、准备一个微信商户,该商户需具备JSAPI支付权限
3、微信商户需要与公众号绑定
4、在微信商户平台设置你的JSAPI支付目录,在微信公众平台设置授权域名
注:详见微信支付官方文档微信JSAPI支付开发步骤
3.2开发3.2.1统一下单在微信发起JSAPI支付之前,商户系统需要先调用统一下单接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易会话标识后再按JSAPI场景生成交易串调起支付。
所以我们需要首先开发后台接口,完成统一下单,并返回订单详情扩展字符串、签名等信息。
/完成统一下单,并返回订单详情扩展字符串、签名等信息@paramopenId@return@throwsException/@RequestMapping(value="/payOrder")@ResponseBodypublicMapString,ObjectpayOrder(StringopenId)throwsException{MapString,ObjectresultMap=newHashMapString,Object();Stringu=RequestUtil.getUUID();//生成UUID,用于随机字符串、商户订单号JSONObjectjsonObj=newJSONObject();jsonObj.put("appid",SystemContant.PUBLIC_ACCOUNT_APPID);//公众号appIdjsonObj.put("mch_id",SystemContant.MCH_ID);//商户IDjsonObj.put("nonce_str",u);//随机字符串jsonObj.put("body","银座汽贸洗车服务");//商品描述jsonObj.put("out_trade_no",u);//商户订单号jsonObj.put("spbill_create_ip","xx.xx.xx.xx");//调用微信支付API的机器IPjsonObj.put("notify_url","http://IP:port/Project/payCallBack");//异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。jsonObj.put("total_fee",Integer.parseInt(String.valueOf(SystemContant.PRETEST_MAP.get("cleanCarFee"))));//支付金额,单位是分jsonObj.put("trade_type","JSAPI");//交易类型JSAPI支付jsonObj.put("openid",openId);//用户在本公众号内的openIdjsonObj.put("sign",RequestUtil.paramSort(jsonObj));//参数排序并生成签名StringunifiedorderXML=RequestUtil.ssl("https://api.mch.weixin.qq.com/pay/unifiedorder",RequestUtil.jsonToXML(jsonObj));//调用微信接口统一下单JSONObjectjsonObjResult=RequestUtil.xmltoJson(unifiedorderXML);//将微信返回的xml数据转换成json数据JSONObjectjsonObjXML=jsonObjResult.getJSONObject("xml");StringreturnCode=jsonObjXML.getString("return_code");//通信标识if(StringUtils.equals("FAIL",returnCode)){//通信失败或签名错误logger.error("调用微信支付通信失败---"+"--xmlStr:"+unifiedorderXML+"--publicAccountOpenId:"+openId);resultMap.put("flag",false);resultMap.put("msg","系统内部错误");resultMap.put("errCodeDes","调用微信支付通信失败");returnresultMap;}StringresultCode=jsonObjXML.getString("result_code");if(StringUtils.equals("FAIL",resultCode)){//当result_code为FAIL时返回错误代码StringerrCodeDes=jsonObjXML.getString("err_code_des");//失败原因StringerrCode=jsonObjXML.getString("err_code");//失败状态码resultMap.put("flag",false);resultMap.put("errCode",errCode);resultMap.put("errCodeDes",errCodeDes);resultMap.put("msg","统一下单失败。");returnresultMap;}else{//下单成功StringprepayId=jsonObjXML.getString("prepay_id");//预支付交易会话标识longtimeStamp=System.currentTimeMillis()/1000;//时间戳JSONObjectjsonObjTemp=newJSONObject();jsonObjTemp.put("appId",SystemContant.PUBLIC_ACCOUNT_APPID);//公众号appIdjsonObjTemp.put("timeStamp",String.valueOf(timeStamp));//时间戳jsonObjTemp.put("nonceStr",u);//随机字符串jsonObjTemp.put("package","prepay_id="+prepayId);//订单详情扩展字符串jsonObjTemp.put("signType","MD5");//签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致Stringsign=RequestUtil.paramSort(jsonObjTemp);//参数排序并生成签名resultMap.put("flag",true);resultMap.put("msg","下单成功");resultMap.put("appId",SystemContant.PUBLIC_ACCOUNT_APPID);resultMap.put("timeStamp",String.valueOf(timeStamp));resultMap.put("nonceStr",u);resultMap.put("packageStr","prepay_id="+prepayId);resultMap.put("paySign",sign);}returnresultMap;}3.2.2微信页面内发起微信支付首先,页面内需要引入微信相关的js:
scriptsrc="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"/script
发起支付:
functionpayOrder(){$.ajax({type:'GET',url:'https://IP:port/xxxxx/payOrder?openId='+openId,dataType:'json',timeout:3000,success:function(data){varorderId=data.nonceStr;WeixinJSBridge.invoke('getBrandWCPayRequest',{"appId":data.appId,//公众号名称,由商户传入"timeStamp":data.timeStamp,//时间戳,自1970年以来的秒数"nonceStr":data.nonceStr,//随机串"package":data.packageStr,"signType":"MD5",//微信签名方式:"paySign":data.paySign//微信签名},function(res){if(res.err_msg=="get_brand_wcpay_request:ok"){payDone(openId,orderId);}else{
}});},error:function(xhr,type){alert('下单失败,请重试!')}})}
可以看到,页面内首先调用后台payOrder接口完成统一下单,并返回发起支付需要的参数值,然后再通过这些参数发起微信支付。如果微信返回的err_msg=="get_brand_wcpay_request:ok",那么执行payDone方法。我们再看下payDone方法代码:
functionpayDone(openId,orderId){$.ajax({type:'GET',url:'https://IP:port/xxxxx/payDone?openId='+openId+'&orderId='+orderId,dataType:'json',timeout:3000,success:function(data){window.location.href="success.html?openId="+openId;},error:function(xhr,type){alert('生成订单失败,请保存支付凭证,联系商家!')}})}
payDone方法中调用了后台payDone接口,我们再来看一下payDone接口代码:
/验证订单是否真正支付成功@paramopenId用户openId@paramorderId商户订单号@return@throwsException/@RequestMapping(value="/payDone")@ResponseBodypublicMapString,ObjectpayDone(StringopenId,StringorderId)throwsException{MapString,ObjectresultMap=newHashMapString,Object();Stringu=RequestUtil.getUUID();JSONObjectjsonObj=newJSONObject();jsonObj.put("appid",SystemContant.PUBLIC_ACCOUNT_APPID);jsonObj.put("mch_id",SystemContant.MCH_ID);jsonObj.put("nonce_str",u);jsonObj.put("out_trade_no",orderId);jsonObj.put("sign",RequestUtil.paramSort(jsonObj));CleanCarOrdercleanCarOrder=newCleanCarOrder();cleanCarOrder.setOpenId(openId);cleanCarOrder.setOutTradeNo(orderId);cleanCarOrder.setTradeType("JSAPI");try{//调用订单查询接口确认订单是否真正的支付成功StringunifiedorderXML=RequestUtil.ssl("https://api.mch.weixin.qq.com/pay/orderquery",RequestUtil.jsonToXML(jsonObj));logger.error("payDoneXML:"+unifiedorderXML);JSONObjectjsonObjResult=RequestUtil.xmltoJson(unifiedorderXML);JSONObjectjsonObjXML=jsonObjResult.getJSONObject("xml");StringreturnCode=jsonObjXML.getString("return_code");//通信标识if(StringUtils.equals("FAIL",returnCode)){//通信失败logger.error("调用微信订单查询接口通信失败---"+"--xmlStr:"+unifiedorderXML+"--orderId:"+orderId);cleanCarOrder.setDataStatus(0);}StringresultCode=jsonObjXML.getString("result_code");if(StringUtils.equals("FAIL",resultCode)){//状态未明确cleanCarOrder.setDataStatus(0);}else{StringtradeState=jsonObjXML.getString("trade_state");//交易彻底成功if(StringUtils.isNotEmpty(tradeState)&&StringUtils.equals("SUCCESS",tradeState)){cleanCarOrder.setDataStatus(1);cleanCarOrder.setResultCode(resultCode);cleanCarOrder.setTimeEnd(jsonObjXML.getString("time_end"));cleanCarOrder.setTotalFee(jsonObjXML.getInt("cash_fee"));cleanCarOrder.setTransactionId(jsonObjXML.getString("transaction_id"));}else{cleanCarOrder.setDataStatus(0);}}}catch(Exceptione){cleanCarOrder.setDataStatus(0);e.printStackTrace();}messageProducer.sendMessage(cleanCarOrder.getDataStatus()==1?"确认交易成功":"未确认交易成功","银座洗车票","o8jb70el0nonB-s4OLrzYBwAMz48","sendSpecifyTemplateMsg","");if(cleanCarService.addCleanCarOrder(cleanCarOrder)1){logger.error("保存用户洗车购买记录失败cleanCarOrder:"+cleanCarOrder);}resultMap.put("status",true);resultMap.put("msg","保存成功");returnresultMap;}从上述代码中可以看到,后台payDone接口功能是根据商户订单号用来查询订单是否成功支付,同时处理其他业务逻辑。为什么微信那边err_msg已经返回了"get_brand_wcpay_request:ok",我们还要主动去查询订单状态呢?这里存在一个问题:

上图是微信支付官方API上的一段话,所以在err_msg返回ok的情况下,我们还需要主动调用订单查询接口或者根据微信的回调来判断订单支付状态。在统一下单的时候存在notify_url参数,这里需要传你的服务器接口地址,在支付完成之后微信会回调该接口通知订单支付状态。
3.2.3注意点在微信页面发起微信支付之前,需要商户系统在服务器端调用统一下单接口发起微信预支付;后台完成统一下单之后,需要再次进行参数排序、生成签名等操作,然后将数据返回给前端,用于前端发起支付;支付完成之后,微信前端返回err_msg=="get_brand_wcpay_request:ok",这并不能保证支付成功,需要主动调用订单查询接口或者根据微信的回调来判断订单支付状态。并且接收微信回调时也要进行签名校验,防止接收到伪回调消息;以上涉及到参数排序、生成签名等操作必须在服务器端完成,前端只负责接收和发送数据。3.2.4效果图
四、小程序支付小程序发起微信支付交易类型也是JSAPI类型,流程步骤和微信网页支付基本相同。
4.1准备工作1、准备一个微信小程序,同时保证该小程序有“微信支付”的权限
2、准备一个微信商户,该商户需具备JSAPI支付权限
3、微信商户需要与小程序绑定
4、在微信商户平台设置你的JSAPI支付目录,在小程序平台设置授权域名
4.2开发和微信网页支付一样,在微信小程序发起支付之前,同样需要商户系统先调用统一下单接口在微信支付服务后台生成预支付交易单。
4.2.1统一下单后台代码和上述微信网页开发后台代码一致:
/调用微信统一下单接口并返回签名等信息@paramopenId@return@throwsException/@RequestMapping(value="/payOrder")@ResponseBodypublicMapString,ObjectpayOrder(StringopenId)throwsException{MapString,ObjectresultMap=newHashMapString,Object();Stringu=RequestUtil.getUUID();JSONObjectjsonObj=newJSONObject();jsonObj.put("appid",SystemContant.WECHAT_APPID);jsonObj.put("mch_id",SystemContant.MCH_ID);jsonObj.put("nonce_str",u);jsonObj.put("body","速挪车服务");jsonObj.put("out_trade_no",u);jsonObj.put("spbill_create_ip","xx.xx.xx.xx");jsonObj.put("notify_url","https://IP:port/xxx/payCallBack");jsonObj.put("total_fee",SystemContant.POSTAGE);jsonObj.put("trade_type","JSAPI");jsonObj.put("openid",openId);jsonObj.put("sign",RequestUtil.paramSort(jsonObj));StringunifiedorderXML=RequestUtil.ssl("https://api.mch.weixin.qq.com/pay/unifiedorder",RequestUtil.jsonToXML(jsonObj));JSONObjectjsonObjResult=RequestUtil.xmltoJson(unifiedorderXML);JSONObjectjsonObjXML=jsonObjResult.getJSONObject("xml");StringreturnCode=jsonObjXML.getString("return_code");//通信标识if(StringUtils.equals("FAIL",returnCode)){//通信失败log.error("调用微信支付通信失败---"+"--xmlStr:"+unifiedorderXML+"--publicAccountOpenId:"+openId);resultMap.put("flag",false);resultMap.put("msg","系统内部错误");resultMap.put("errCodeDes","调用微信支付通信失败");returnresultMap;}StringresultCode=jsonObjXML.getString("result_code");if(StringUtils.equals("FAIL",resultCode)){//状态未明确//请求查询接口确认状态信息StringerrCodeDes=jsonObjXML.getString("err_code_des");//失败原因StringerrCode=jsonObjXML.getString("err_code");//失败状态码resultMap.put("flag",false);resultMap.put("errCode",errCode);resultMap.put("errCodeDes",errCodeDes);resultMap.put("msg","统一下单失败。");returnresultMap;}else{//下单成功StringprepayId=jsonObjXML.getString("prepay_id");longtimeStamp=System.currentTimeMillis()/1000;JSONObjectjsonObjTemp=newJSONObject();jsonObjTemp.put("appId",SystemContant.WECHAT_APPID);jsonObjTemp.put("timeStamp",String.valueOf(timeStamp));jsonObjTemp.put("nonceStr",u);jsonObjTemp.put("package","prepay_id="+prepayId);jsonObjTemp.put("signType","MD5");Stringsign=RequestUtil.paramSort(jsonObjTemp);resultMap.put("flag",true);resultMap.put("msg","下单成功");resultMap.put("appId",SystemContant.WECHAT_APPID);resultMap.put("timeStamp",String.valueOf(timeStamp));resultMap.put("nonceStr",u);resultMap.put("packageStr","prepay_id="+prepayId);resultMap.put("paySign",sign);}returnresultMap;}4.2.2微信小程序发起支付wx.request({url:serverUrl+'payOrder',method:'GET',data:{openId:app.globalData.openId},success:function(res){if(res.data.flag==true){varoutTradeNo=res.data.nonceStr;wx.requestPayment({'timeStamp':res.data.timeStamp,'nonceStr':res.data.nonceStr,'package':res.data.packageStr,'signType':'MD5','paySign':res.data.paySign,'success':function(res){console.log("success:"+res);//支付成功,保存申请记录wx.request({url:serverUrl+'saveUserCodeApply',method:'GET',data:{openId:app.globalData.openId,area:that.data.region[0]+"-"+that.data.region[1]+"-"+that.data.region[2],address:e.detail.value.address,tel:e.detail.value.tel,name:e.detail.value.userName,outTradeNo:outTradeNo,},success:function(res){if(res.data.status){wx.showToast({title:res.data.errmsg,icon:'success',duration:2000})//跳转页面}else{//提示失败wx.showModal({title:'提示',content:res.data.errmsg,success(res){}})}}})},'fail':function(res){console.log("fail:"+res);},'complete':function(res){console.log("complete:"+res);}})}else{wx.showModal({title:'系统提示',content:res.data.msg,showCancel:false})}}})微信小程序调用后台payOrder接口完成统一下单,同时根据接口返回的参数发起微信支付,当微信requestPayment请求返回success时代表支付成功。这个地方微信官方文档上并没有提到是否存在风险,必要的情况下也可以通过主动查询或者微信回调来校验订单状态。
4.2.3注意点注意点同3.2.3。
4.2.4效果图
以上内容介绍了微信支付开发中常见的公众号发红包、企业付款、微信网页支付、微信小程序支付等功能的开发流程。
如有任何疑问,可关注公众号留言,工程师将尽快回答您的问题。公众号二维码:

版权声明

即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。

产品经理

手机 : 13312967497

擅长 : 小程序流量变现

扫码领取礼包

热门模板

  • 头条
  • 搜狐
  • 微博
  • 百家
  • 一点资讯
  • 知乎