E企盈营销工具技术服务商 热线:4006-838-530

微信流水,微信小程序调用微信支付接口

E企盈直播平台营销卖货系统

前言:应项目要求,需要使用微信小程序做支付,写完后告知手续费太高方案不予通过(宝宝心里苦,但宝宝不说)。此次开发在因站在巨人的肩膀上顺利完成。微信支付文档传送门:1.开发工具:Eclipse+Tomcat+微信web开发工具2.开发环境:java+maven3.开发前准备:3.1所需材料小程序的appid,APPsecret,支付商户号(mch_id),商户密钥(key),付款用户的openid。申请接入微信商户地址:3.2开发模式本次开发采用的开发模式是:普通模式,适用于有自己开发团队或外包开发商的直连商户收款。开发者申请自己的appid和mch_id,两者需具备绑定关系,以此来使用微信支付提供的开放接口,对用户提供服务。4开发4.1小程序端wx.request({url:address+’wxPay’,data:{openId:openId//amount:amount,//openId:openId},header:{‘content-type’:’application/x-www-form-urlencoded’//默认值},method:”POST”,success:function(res){console.log(res);that.doWxPay(res.data);},fail:function(err){wx.showToast({icon:”none”,title:’服务器异常,清稍候再试’})},});doWxPay(param){//小程序发起微信支付wx.requestPayment({timeStamp:param.data.timeStamp,//记住,这边的timeStamp一定要是字符串类型的,不然会报错nonceStr:param.data.nonceStr,package:param.data.package,signType:’MD5′,paySign:param.data.paySign,success:function(event){//successconsole.log(event);wx.showToast({title:’支付成功’,icon:’success’,duration:2000});},fail:function(error){//failconsole.log(“支付失败”)console.log(error)},complete:function(){//completeconsole.log(“paycomplete”)}});},4.2java后台4.2.1PayUtil.javaprivatestaticLoggerlogger=Logger.getLogger(PayUtil.class);publicstaticJSONObjectwxPay(Stringopenid,HttpServletRequestrequest){JSONObjectjson=newJSONObject();try{//生成的随机字符串Stringnonce_str=Util.getRandomStringByLength(32);//商品名称Stringbody=newString(WXConst.title.getBytes(“ISO-8859-1″),”UTF-8″);//获取本机的ip地址Stringspbill_create_ip=Util.getIpAddr(request);StringorderNo=WXConst.orderNo;Stringmoney=”1”;//支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败MapString,StringpackageParams=newHashMapString,String();packageParams.put(“appid”,WXConst.appId);packageParams.put(“mch_id”,WXConst.mch_id);packageParams.put(“nonce_str”,nonce_str);packageParams.put(“body”,body);packageParams.put(“out_trade_no”,orderNo);//商户订单号packageParams.put(“total_fee”,money);packageParams.put(“spbill_create_ip”,spbill_create_ip);packageParams.put(“notify_url”,WXConst.notify_url);packageParams.put(“trade_type”,WXConst.TRADETYPE);packageParams.put(“openid”,openid);//除去数组中的空值和签名参数packageParams=PayUtil.paraFilter(packageParams);Stringprestr=PayUtil.createLinkString(packageParams);//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串//MD5运算生成签名,这里是第一次签名,用于调用统一下单接口Stringmysign=PayUtil.sign(prestr,WXConst.key,”utf-8″).toUpperCase();logger.info(“=======================第一次签名:”+mysign+”=====================”);//拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去Stringxml=”xmlversion=’1.0’encoding=’gbk'”+”appid”+WXConst.appId+”/appid”+”body![CDATA[“+body+”]]/body”+”mch_id”+WXConst.mch_id+”/mch_id”+”nonce_str”+nonce_str+”/nonce_str”+”notify_url”+WXConst.notify_url+”/notify_url”+”openid”+openid+”/openid”+”out_trade_no”+orderNo+”/out_trade_no”+”spbill_create_ip”+spbill_create_ip+”/spbill_create_ip”+”total_fee”+money+”/total_fee”+”trade_type”+WXConst.TRADETYPE+”/trade_type”+”sign”+mysign+”/sign”+”/xml”;System.out.println(“调试模式_统一下单接口请求XML数据:”+xml);//调用统一下单接口,并接受返回的结果Stringresult=PayUtil.httpRequest(WXConst.pay_url,”POST”,xml);System.out.println(“调试模式_统一下单接口返回XML数据:”+result);//将解析结果存储在HashMap中Mapmap=PayUtil.doXMLParse(result);Stringreturn_code=(String)map.get(“return_code”);//返回状态码//返回给移动端需要的参数MapString,Objectresponse=newHashMapString,Object();if(return_code==”SUCCESS”||return_code.equals(return_code)){//业务结果Stringprepay_id=(String)map.get(“prepay_id”);//返回的预付单信息response.put(“nonceStr”,nonce_str);response.put(“package”,”prepay_id=”+prepay_id);LongtimeStamp=System.currentTimeMillis()/1000;response.put(“timeStamp”,timeStamp+””);//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误StringstringSignTemp=”appId=”+WXConst.appId+”&nonceStr=”+nonce_str+”&package=prepay_id=”+prepay_id+”&signType=”+WXConst.SIGNTYPE+”&timeStamp=”+timeStamp;//再次签名,这个签名用于小程序端调用wx.requesetPayment方法StringpaySign=PayUtil.sign(stringSignTemp,WXConst.key,”utf-8″).toUpperCase();logger.info(“=======================第二次签名:”+paySign+”=====================”);response.put(“paySign”,paySign);//更新订单信息//业务逻辑代码}response.put(“appid”,WXConst.appId);json.put(“errMsg”,”OK”);//json.setSuccess(true);json.put(“data”,response);//json.setData(response);}catch(Exceptione){e.printStackTrace();json.put(“errMsg”,”Failed”);//json.setSuccess(false);//json.setMsg(“发起失败”);}returnjson;}/签名字符串@paramtext需要签名的字符串@paramkey密钥@paraminput_charset编码格式@return签名结果/publicstaticStringsign(Stringtext,Stringkey,Stringinput_charset){text=text+”&key=”+key;returnDigestUtils.md5Hex(getContentBytes(text,input_charset));}/签名字符串@paramtext需要签名的字符串@paramsign签名结果@paramkey密钥@paraminput_charset编码格式@return签名结果/publicstaticbooleanverify(Stringtext,Stringsign,Stringkey,Stringinput_charset){text=text+key;Stringmysign=DigestUtils.md5Hex(getContentBytes(text,input_charset));if(mysign.equals(sign)){returntrue;}else{returnfalse;}}/@paramcontent@paramcharset@return@throwsSignatureException@throwsUnsupportedEncodingException/publicstaticbyte[]getContentBytes(Stringcontent,Stringcharset){if(charset==null||””.equals(charset)){returncontent.getBytes();}try{returncontent.getBytes(charset);}catch(UnsupportedEncodingExceptione){thrownewRuntimeException(“MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:”+charset);}}/生成6位或10位随机数paramcodeLength(多少位)@return/publicstaticStringcreateCode(intcodeLength){Stringcode=””;for(inti=0;icodeLength;i++){code+=(int)(Math.random()9);}returncode;}@SuppressWarnings(“unused”)privatestaticbooleanisValidChar(charch){if((ch=’0’&&ch=’9′)||(ch=’A’&&ch=’Z’)||(ch=’a’&&ch=’z’))returntrue;if((ch=0x4e00&&ch=0x7fff)||(ch=0x8000&&ch=0x952f))returntrue;//简体中文汉字编码returnfalse;}/除去数组中的空值和签名参数@paramsArray签名参数组@return去掉空值与签名参数后的新签名参数组/publicstaticMapString,StringparaFilter(MapString,StringsArray){MapString,Stringresult=newHashMapString,String();if(sArray==null||sArray.size()=0){returnresult;}for(Stringkey:sArray.keySet()){Stringvalue=sArray.get(key);if(value==null||value.equals(“”)||key.equalsIgnoreCase(“sign”)||key.equalsIgnoreCase(“sign_type”)){continue;}result.put(key,value);}returnresult;}/把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串@paramparams需要排序并参与字符拼接的参数组@return拼接后字符串/publicstaticStringcreateLinkString(MapString,Stringparams){ListStringkeys=newArrayListString(params.keySet());Collections.sort(keys);Stringprestr=””;for(inti=0;ikeys.size();i++){Stringkey=keys.get(i);Stringvalue=params.get(key);if(i==keys.size()-1){//拼接时,不包括最后一个&字符prestr=prestr+key+”=”+value;}else{prestr=prestr+key+”=”+value+”&”;}}returnprestr;}/@paramrequestUrl请求地址@paramrequestMethod请求方法@paramoutputStr参数/publicstaticStringhttpRequest(StringrequestUrl,StringrequestMethod,StringoutputStr){//创建SSLContextStringBufferbuffer=null;try{URLurl=newURL(requestUrl);HttpURLConnectionconn=(HttpURLConnection)url.openConnection();conn.setRequestMethod(requestMethod);conn.setDoOutput(true);conn.setDoInput(true);conn.connect();//往服务器端写内容if(null!=outputStr){OutputStreamos=conn.getOutputStream();os.write(outputStr.getBytes(“utf-8″));os.close();}//读取服务器端返回的内容InputStreamis=conn.getInputStream();InputStreamReaderisr=newInputStreamReader(is,”utf-8″);BufferedReaderbr=newBufferedReader(isr);buffer=newStringBuffer();Stringline=null;while((line=br.readLine())!=null){buffer.append(line);}br.close();}catch(Exceptione){e.printStackTrace();}returnbuffer.toString();}publicstaticStringurlEncodeUTF8(Stringsource){Stringresult=source;try{result=java.net.URLEncoder.encode(source,”UTF-8″);}catch(UnsupportedEncodingExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}returnresult;}/解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。@paramstrxml@return@throwsJDOMException@throwsIOException/publicstaticMapdoXMLParse(Stringstrxml)throwsException{if(null==strxml||””.equals(strxml)){returnnull;}Mapm=newHashMap();InputStreamin=String2Inputstream(strxml);SAXBuilderbuilder=newSAXBuilder();Documentdoc=builder.build(in);Elementroot=doc.getRootElement();Listlist=root.getChildren();Iteratorit=list.iterator();while(it.hasNext()){Elemente=(Element)it.next();Stringk=e.getName();Stringv=””;Listchildren=e.getChildren();if(children.isEmpty()){v=e.getTextNormalize();}else{v=getChildrenText(children);}m.put(k,v);}//关闭流in.close();returnm;}/获取子结点的xml@paramchildren@returnString/publicstaticStringgetChildrenText(Listchildren){StringBuffersb=newStringBuffer();if(!children.isEmpty()){Iteratorit=children.iterator();while(it.hasNext()){Elemente=(Element)it.next();Stringname=e.getName();Stringvalue=e.getTextNormalize();Listlist=e.getChildren();sb.append(“”+name+””);if(!list.isEmpty()){sb.append(getChildrenText(list));}sb.append(value);sb.append(“/”+name+””);}}returnsb.toString();}publicstaticInputStreamString2Inputstream(Stringstr){returnnewByteArrayInputStream(str.getBytes());}publicstaticvoidwxNotify(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{BufferedReaderbr=newBufferedReader(newInputStreamReader((ServletInputStream)request.getInputStream()));Stringline=null;StringBuildersb=newStringBuilder();while((line=br.readLine())!=null){sb.append(line);}br.close();//sb为微信返回的xmlStringnotityXml=sb.toString();StringresXml=””;System.out.println(“接收到的报文:”+notityXml);Mapmap=PayUtil.doXMLParse(notityXml);StringreturnCode=(String)map.get(“return_code”);if(“SUCCESS”.equals(returnCode)){//验证签名是否正确if(PayUtil.verify(PayUtil.createLinkString(map),(String)map.get(“sign”),WXConst.key,”utf-8″)){/此处添加自己的业务逻辑代码start//此处添加自己的业务逻辑代码end///通知微信服务器已经支付成功resXml=”xml”+”return_code![CDATA[SUCCESS]]/return_code”+”return_msg![CDATA[OK]]/return_msg”+”/xml”;}}else{resXml=”xml”+”return_code![CDATA[FAIL]]/return_code”+”return_msg![CDATA[报文为空]]/return_msg”+”/xml”;}System.out.println(resXml);System.out.println(“微信支付回调数据结束”);BufferedOutputStreamout=newBufferedOutputStream(response.getOutputStream());out.write(resXml.getBytes());out.flush();out.close();}4.2.2Util.java/Util工具类方法获取一定长度的随机字符串,范围0-9,a-z@paramlength:指定字符串长度@return一定长度的随机字符串/publicstaticStringgetRandomStringByLength(intlength){Stringbase=”abcdefghijklmnopqrstuvwxyz0123456789″;Randomrandom=newRandom();StringBuffersb=newStringBuffer();for(inti=0;ilength;i++){intnumber=random.nextInt(base.length());sb.append(base.charAt(number));}returnsb.toString();}/Util工具类方法获取真实的ip地址@paramrequest@return/publicstaticStringgetIpAddr(HttpServletRequestrequest){Stringip=request.getHeader(“X-Forwarded-For”);if(StringUtils.isNotEmpty(ip)&&!”unKnown”.equalsIgnoreCase(ip)){//多次反向代理后会有多个ip值,第一个ip才是真实ipintindex=ip.indexOf(“,”);if(index!=-1){returnip.substring(0,index);}else{returnip;}}ip=request.getHeader(“X-Real-IP”);if(StringUtils.isNotEmpty(ip)&&!”unKnown”.equalsIgnoreCase(ip)){returnip;}returnrequest.getRemoteAddr();}4.2.3WXConst.java//微信小程序appidpublicstaticStringappId=””;//微信小程序appsecretpublicstaticStringappSecret=””;//微信支付主体publicstaticString;publicstaticStringorderNo=””;//微信商户号publicstaticStringmch_id=””;//微信支付的商户密钥publicstaticfinalStringkey=””;//获取微信Openid的请求地址publicstaticStringWxGetOpenIdUrl=””;//支付成功后的服务器回调urlpublicstaticfinalStringnotify_url=”https://api.weixin.qq.com/sns/jscode2session”;//签名方式publicstaticfinalStringSIGNTYPE=”MD5″;//交易类型publicstaticfinalStringTRADETYPE=”JSAPI”;//微信统一下单接口地址publicstaticfinalStringpay_url=”https://api.mch.weixin.qq.com/pay/unifiedorder”;5可能出现的问题5.1商户号会出现一个什么异常我忘了,重置一下微信商户密钥就好了5.2中文参数Stringbody=newString(WXConst.title.getBytes(“ISO-8859-1″),”UTF-8”);这行很重要,如果报参数索引-2异常,很可能是出现了中文,对中文进行如上处理即可通过。5.3invalidspbill_create_ip使用微信web开发工具直接测试的,出现了这个问题,调试记得用真机哦。整个小程序前后端一个人开发,测试成功上线前夕又嫌弃微信支付收取的手续费(0.6%)太高,结算周期(T+7)太长,所以就被无情抛弃了,这个月项目重启(2018-11)和工商银行达成一致,直接转账到对公账户,目前项目进展顺利已上线。改需求请先扫码(小声bb)

赞(0) 打赏
未经允许不得转载:E企盈小程序开发-热线:4006-838-530 » 微信流水,微信小程序调用微信支付接口
分享到: 更多 (0)
E企盈小程序直播营销卖货系统
E企盈直播平台营销卖货系统

评论 抢沙发

E企盈小程序开发

联系我们联系我们

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏