java实现网站微信扫码支付
一、网站微信扫码支付开发并没有现成的java示例,总结一下自己微信扫码支付心得
二、首先去微信公众平台申请账户
https://mp.weixin.qq.com
**
三、账户开通、开发者认证之后就可以进行微信支付开发了
1、微信统一下单接口调用获取预支付id,以及生成二维码所需的codeUrl
/** *保存订单,并生成二维码所需的codeUrl * *@paramrequest *@paramresponse *@paramnotifyURLBuf *@paramorder *@return *@throwsException */ @Override publicMapgetWechatOrderInfo(Stringip,Cuseruser,StringnotifyUrl,Orderorder)throwsException{ Map resultMap=newHashMap (); //生成并保存订单 order.setUserId(user.getId()); //支付方式0:银联1:支付宝2:网上银行3:微信4:其他 order.setPayType("3"); //生成订单号 order.setOrderNo(OrderNoGenerator.getOrderNo()); //订单类型1:消费2:退款 order.setOrderType("1"); //订单创建时间 order.setCreateTime(newDate()); //订单更新时间 order.setUpdateTime(newDate()); //订单状态0:交易中1:完成2:已取消 order.setOrderStatus("0"); //付款状态0:失败1:成功2、待付款 order.setPayStatus("2"); //设置订单失效时间 Calendarcalendar=Calendar.getInstance(); calendar.add(Calendar.HOUR,2); order.setExpireTime(calendar.getTime()); IntegerorderId=this.balanceDao.saveOrder(order); Map payPreIdMap=newHashMap<>(); payPreIdMap=WechatUtil.getPayPreId(String.valueOf(orderId),"体检报告",notifyUrl,ip, String.valueOf((order.getMoney().multiply(newBigDecimal(100)).intValue())),orderId.toString()); StringprePayId=payPreIdMap.get("prepay_id"); //更新 order.setId(orderId); order.setPrepayId(prePayId); order.setCodeUrl(payPreIdMap.get("code_url")); this.balanceDao.updateOrder(order); //returnWechatUtil.QRfromGoogle(order.getCodeUrl(),300,0); resultMap.put("codeUrl",order.getCodeUrl()); resultMap.put("orderId",String.valueOf(order.getId())); returnresultMap; }
此方法返回的数据如下
2、服务器端接受微信支付结果通知
/** *保存微信通知结果 * *@paramrequest *@paramresponse *@return *@throwsException */ @Override publicStringsaveWechatNotify(StringnotifyInfoXml)throwsException{ MapnoticeMap=XMLUtil.doXMLParse(notifyInfoXml); //这个其实是订单的id StringoutTradeNo=noticeMap.get("out_trade_no"); Orderorder=this.balanceDao.getOrderById(Integer.valueOf(outTradeNo)); //如果支付通知信息不为,说明请求已经处理过,直接返回 if(StringUtil.isNotEmpty(order.getNotifyInfo())){ return"SUCCESS"; } Stringsign=noticeMap.get("sign"); noticeMap.remove("sign"); //验签通过 if(WechatUtil.getSignVeryfy(noticeMap,sign)){ //通信成功此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断 if("SUCCESS".equals(noticeMap.get("return_code"))){ //交易成功 if("SUCCESS".equals(noticeMap.get("result_code"))){ //商户订单号 //订单更新时间 order.setUpdateTime(newDate()); //------------------------------ //处理业务开始 //------------------------------ //是否交易成功,1:成功0:失败 //微信支付成功 order.setPayStatus("1"); //订单状态0:交易中1:完成2:已取消 order.setOrderStatus("1"); //保存通知信息 order.setNotifyInfo(notifyInfoXml); this.balanceDao.updateOrder(order); //处理业务完毕 }else{ //错误时,返回结果未签名,记录retcode、retmsg看失败详情。 logger.info("查询验证签名失败或业务错误"); logger.info("retcode:"+noticeMap.get("retcode")+"retmsg:"+noticeMap.get("retmsg")); } return"SUCCESS"; }else{ logger.info("后台调用通信失败"); } return"SUCCESS"; }else{ logger.info("通知签名验证失败"); } returnnull; }
3、上面代码用到的工具方法都在WechatUtil.java工具类中
packagecom.caifu.tencent.common; importjava.io.IOException; importjava.net.URISyntaxException; importjava.net.URLEncoder; importjava.util.ArrayList; importjava.util.Collections; importjava.util.HashMap; importjava.util.LinkedList; importjava.util.List; importjava.util.Map; importjava.util.Random; importorg.apache.commons.httpclient.HttpStatus; importorg.apache.http.NameValuePair; importorg.apache.http.client.config.RequestConfig; importorg.apache.http.client.methods.CloseableHttpResponse; importorg.apache.http.client.methods.HttpPost; importorg.apache.http.client.utils.URIBuilder; importorg.apache.http.entity.StringEntity; importorg.apache.http.impl.client.CloseableHttpClient; importorg.apache.http.impl.client.HttpClients; importorg.apache.http.message.BasicNameValuePair; importorg.apache.http.util.EntityUtils; importorg.jdom2.JDOMException; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; importcom.caifu.login.utils.XMLUtil; publicclassWechatUtil{ privatestaticLoggerlogger=LoggerFactory.getLogger(WechatUtil.class); publicstaticfinalStringTAG="Wechat.Util"; privatestaticfinalinttimeout=5000; publicstaticbyte[]httpPost(Stringurl,Stringentity)throwsURISyntaxException,IOException{ if(url==null||url.length()==0){ logger.info(TAG,"httpPost,urlisnull"); returnnull; } CloseableHttpClienthttpClient=HttpClients.createDefault(); URIBuilderuriBuilder=newURIBuilder(url); HttpPosthttpPost=newHttpPost(uriBuilder.build()); RequestConfigrequestConfig=RequestConfig.custom().setSocketTimeout(timeout).setConnectionRequestTimeout(timeout).setConnectTimeout(timeout).build(); httpPost.setConfig(requestConfig); //避免汉字乱码导致请求失败, httpPost.setEntity(newStringEntity(entity,"UTF-8")); CloseableHttpResponseresp=null; try{ resp=httpClient.execute(httpPost); if(resp.getStatusLine().getStatusCode()!=HttpStatus.SC_OK){ logger.info(TAG,"httpGetfail,statuscode="+resp.getStatusLine().getStatusCode()); returnnull; } returnEntityUtils.toByteArray(resp.getEntity()); }catch(Exceptione){ logger.info(TAG,"httpPostexception,e="+e.getMessage()); e.printStackTrace(); returnnull; }finally{ if(httpClient!=null){ httpClient.close(); } if(resp!=null){ resp.close(); } } } /** *把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串 * *@paramparams *需要排序并参与字符拼接的参数组 *@return拼接后字符串 */ publicstaticStringcreateLinkString(Mapparams){ List keys=newArrayList (params.keySet()); Collections.sort(keys); Stringprestr=""; for(inti=0;i Params,Stringsign){ //过滤空值、sign与sign_type参数 //Map sParaNew=AlipayCore.paraFilter(Params); //获取待签名字符串 StringpreSignStr=createLinkString(Params); preSignStr+="&key="+Configure.getKey(); //获得签名验证结果 StringresultSign=MD5.MD5Encode(preSignStr).toUpperCase(); //StringresultSign=MD5Util.MD5Encode(preSignStr.toString(), //"UTF-8").toLowerCase(); if(sign.equals(resultSign)){ returntrue; }else{ returnfalse; } } /** *装配xml,生成请求prePayId所需参数 * *@paramparams *@return */ publicstaticStringtoXml(List params){ StringBuildersb=newStringBuilder(); sb.append(" "); for(inti=0;i "); returnsb.toString(); } /** *生成签名 */ publicstaticStringgenPackageSign(List"); sb.append(params.get(i).getValue()); sb.append(""+params.get(i).getName()+">"); } sb.append(" params){ StringBuildersb=newStringBuilder(); for(inti=0;i "); List packageParams=newLinkedList (); packageParams.add(newBasicNameValuePair("appid",Configure.getAppid())); packageParams.add(newBasicNameValuePair("body",body)); packageParams.add(newBasicNameValuePair("mch_id",Configure.getMchid())); packageParams.add(newBasicNameValuePair("nonce_str",nonceStr)); packageParams.add(newBasicNameValuePair("notify_url",noticeUrl)); packageParams.add(newBasicNameValuePair("out_trade_no",goodOrderNo)); packageParams.add(newBasicNameValuePair("product_id",productId)); packageParams.add(newBasicNameValuePair("spbill_create_ip",ip)); packageParams.add(newBasicNameValuePair("total_fee",totalFee)); packageParams.add(newBasicNameValuePair("trade_type","NATIVE")); Stringsign=genPackageSign(packageParams); packageParams.add(newBasicNameValuePair("sign",sign)); Stringxmlstring=toXml(packageParams); returnxmlstring; }catch(Exceptione){ logger.info("genProductArgsfail,ex="+e.getMessage()); returnnull; } } /** *生成支付签名 * *@paramparams *@return */ publicstaticStringgenAppSign(List params){ StringBuildersb=newStringBuilder(); for(inti=0;i genPayReq(StringprepayId){ Map resultMap=newHashMap (); StringtimeStamp=getTimeStamp(); StringnonceStr=getNonceStr(); List signParams=newLinkedList (); signParams.add(newBasicNameValuePair("appid",Configure.getAppid())); signParams.add(newBasicNameValuePair("noncestr",nonceStr)); signParams.add(newBasicNameValuePair("package","Sign=WXPay")); signParams.add(newBasicNameValuePair("partnerid",Configure.getMchid())); signParams.add(newBasicNameValuePair("prepayid",prepayId)); signParams.add(newBasicNameValuePair("timestamp",timeStamp)); Stringsign=genAppSign(signParams); resultMap.put("appid",Configure.getAppid()); resultMap.put("noncestr",nonceStr); resultMap.put("packageValue","Sign=WXPay"); resultMap.put("partnerid",Configure.getMchid()); resultMap.put("prepayid",prepayId); resultMap.put("timestamp",timeStamp); resultMap.put("sign",sign); returnresultMap; } /** *微信支付生成预支付订单 * *@throwsIOException *@throwsJDOMException */ publicstaticMap getPayPreId(StringgoodOrderNo,Stringbody,StringnoticeUrl,Stringip,StringtotalFee,StringproductId)throwsException{ StringparamsXml=genProductArgs(goodOrderNo,body,noticeUrl,ip,totalFee,productId); logger.info("orion",paramsXml); byte[]buf=WechatUtil.httpPost(Configure.UNIFIEDORDER_API,paramsXml); StringcontentXml=newString(buf); Map resultMap=XMLUtil.doXMLParse(contentXml); returnresultMap; } publicstaticStringgetNonceStr(){ Randomrandom=newRandom(); returnMD5.MD5Encode(String.valueOf(random.nextInt(10000))); } publicstaticStringgetTimeStamp(){ returnString.valueOf(System.currentTimeMillis()/1000); } /** *生成支付二维码 *@paramrequest *@paramresponse *@paramwidth *@paramheight *@paramtext微信生成预定id时,返回的codeUrl */ publicstaticvoidgetQRcode(HttpServletRequestrequest,HttpServletResponseresponse,Integerwidth,Integerheight,Stringtext){ if(width==null){ width=300; } if(height==null){ height=300; } Stringformat="jpg"; Hashtablehints=newHashtable(); hints.put(EncodeHintType.CHARACTER_SET,"utf-8"); BitMatrixbitMatrix; try{ bitMatrix=newMultiFormatWriter().encode(text,BarcodeFormat.QR_CODE,width,height,hints); MatrixToImageWriter.writeToStream(bitMatrix,format,response.getOutputStream()); }catch(WriterExceptione){ e.printStackTrace(); }catch(IOExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace(); } } }
生成二维码需要两jar
com.google.zxing core 3.3.0 com.google.zxing javase 3.3.0
4、下面是用到的配置类
packagecom.caifu.tencent.common; /** *User:rizenguo *Date:2014/10/29 *Time:14:40 *这里放置各种配置数据 */ publicclassConfigure{ //这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中) //每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证 //收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改 privatestaticStringkey="A6gB0Dy4dsfdssuPCPsdfdshkSCDQcr3eXS"; privatestaticStringappSecret="7584sdfdsfe4f26fadsfsdfs56f10728a"; //微信分配的公众号ID(开通公众号之后可以获取到) privatestaticStringappID="wxaf0b86sdfsdf8afbf"; //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) privatestaticStringmchID="14012313702"; //受理模式下给子商户分配的子商户号 privatestaticStringsubMchID=""; //HTTPS证书的本地路径 privatestaticStringcertLocalPath=""; //HTTPS证书密码,默认密码等于商户号MCHID privatestaticStringcertPassword=""; //是否使用异步线程的方式来上报API测速,默认为异步模式 privatestaticbooleanuseThreadToDoReport=true; //机器IP privatestaticStringip=""; //以下是几个API的路径: //1)被扫支付API publicstaticStringUNIFIEDORDER_API="https://api.mch.weixin.qq.com/pay/unifiedorder"; publicstaticStringPAY_API="https://api.mch.weixin.qq.com/pay/micropay"; //2)被扫支付查询API publicstaticStringPAY_QUERY_API="https://api.mch.weixin.qq.d/pay/orderquery"; //3)退款API publicstaticStringREFUND_API="https://api.mch.weixin.qq.com/secapi/pay/refund"; //4)退款查询API publicstaticStringREFUND_QUERY_API="https://api.mch.weixin.qq.com/pay/refundquery"; //5)撤销API publicstaticStringREVERSE_API="https://api.mch.weixin.qq.com/secapi/pay/reverse"; //6)下载对账单API publicstaticStringDOWNLOAD_BILL_API="https://api.mch.weixin.qq.com/pay/downloadbill"; //7)统计上报API publicstaticStringREPORT_API="https://api.mch.weixin.qq.com/payitil/report"; publicstaticbooleanisUseThreadToDoReport(){ returnuseThreadToDoReport; } publicstaticvoidsetUseThreadToDoReport(booleanuseThreadToDoReport){ Configure.useThreadToDoReport=useThreadToDoReport; } publicstaticStringHttpsRequestClassName="com.tencent.common.HttpsRequest"; publicstaticvoidsetKey(Stringkey){ Configure.key=key; } publicstaticvoidsetAppID(StringappID){ Configure.appID=appID; } publicstaticvoidsetMchID(StringmchID){ Configure.mchID=mchID; } publicstaticvoidsetSubMchID(StringsubMchID){ Configure.subMchID=subMchID; } publicstaticvoidsetCertLocalPath(StringcertLocalPath){ Configure.certLocalPath=certLocalPath; } publicstaticvoidsetCertPassword(StringcertPassword){ Configure.certPassword=certPassword; } publicstaticvoidsetIp(Stringip){ Configure.ip=ip; } publicstaticStringgetKey(){ returnkey; } publicstaticStringgetAppid(){ returnappID; } publicstaticStringgetMchid(){ returnmchID; } publicstaticStringgetSubMchid(){ returnsubMchID; } publicstaticStringgetCertLocalPath(){ returncertLocalPath; } publicstaticStringgetCertPassword(){ returncertPassword; } publicstaticStringgetIP(){ returnip; } publicstaticvoidsetHttpsRequestClassName(Stringname){ HttpsRequestClassName=name; } }
在这里需要注意的配置
privatestaticStringkey=“A6gB0Dy4dsfdssuPCPsdfdshkSCDQcr3eXS”;
这里的key是登陆https://pay.weixin.qq.com/index.php/core/info(微信商户平台)设置的api_key
5、xml解析工具类
packagecom.caifu.login.utils; importjava.io.ByteArrayInputStream; importjava.io.IOException; importjava.io.InputStream; importjava.util.HashMap; importjava.util.Iterator; importjava.util.List; importjava.util.Map; importjavax.servlet.http.HttpServletRequest; importorg.dom4j.io.SAXReader; importorg.jdom2.Document; importorg.jdom2.Element; importorg.jdom2.JDOMException; importorg.jdom2.input.SAXBuilder; /** *xml工具类 * *@authormiklchen * */ publicclassXMLUtil{ /** *解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。 * *@paramstrxml *@return *@throwsJDOMException *@throwsIOException */ publicstaticMapdoXMLParse(Stringstrxml)throwsJDOMException,IOException{ strxml=strxml.replaceFirst("encoding=\".*\"","encoding=\"UTF-8\""); if(null==strxml||"".equals(strxml)){ returnnull; } Mapm=newHashMap(); InputStreamin=newByteArrayInputStream(strxml.getBytes("UTF-8")); 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=XMLUtil.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(XMLUtil.getChildrenText(list)); } sb.append(value); sb.append(""+name+">"); } } returnsb.toString(); } /** *将requestxml通知结果转出啊成map *@paramrequest *@return *@throwsException */ publicstaticMapparseXml(HttpServletRequestrequest)throwsException{ //解析结果存储在HashMap Map map=newHashMap (); InputStreaminputStream=request.getInputStream(); //读取输入流 SAXReaderreader=newSAXReader(); org.dom4j.Documentdocument=reader.read(inputStream); //得到xml根元素 org.dom4j.Elementroot=document.getRootElement(); //得到根元素的所有子节点 List elementList=root.elements(); //遍历所有子节点 for(org.dom4j.Elemente:elementList) map.put(e.getName(),e.getText()); //释放资源 inputStream.close(); inputStream=null; returnmap; } }
6、整个后台服务已经完成,最后关闭页面微信支付二维码,告知用户支付已经完成了
varf; /*定时任务方法,异步请求去查询订单是否支付*/ functionGetOrder(){ varorderId=$('#orderId').val(); if(orderId!=''){ $.ajax({ url:"${base}/balance/auth/isPay?orderId="+orderId, type:"GET", async:false, success:function(d){ if(d=="1"){ //当获取到微信支付结果时,关闭二维码div $(".weixinpay").css("display","none"); $("#zhichutankuang").css("display","block"); ////当获取到微信支付结果时,关闭定时任务 clearInterval(f); //layer.alert('付款成功',{ //skin:'layui-layer-molv',//样式类名 //closeBtn:0 //},function(){ //location.href="${base}/balance/auth/presentation?tjNo="+$("#tjNo").val(); //}); } } }); } } //异步请求获取生成二维码的url $(".paylast").click(function(){ var$payType=$('input:radio:checked').val(); var$money=$("#money").val(); var$tjReportType=$("#tjReportType").val(); var$tjNo=$("#tjNo").val(); $.ajax({ url:"${base}/balance/auth/wechatInfo", type:"POST", async:false, data:{ payType:$payType, money:$money, tjNo:$tjNo, tjReportType:$tjReportType }, success:function(d){ if(d.resultCode=="1000"){ //当请求成功时,设置二维码图片地址 $("#codeImg").attr('src',d.obj); $("#orderId").val(d.attributes.orderId); ////当请求成功时,启动定时任务,每隔3秒去后台查询一次订单是否成功 f=setInterval(GetOrder,3000); //GetOrder(true); } } }); $(".selpaycon").css("display","none"); $(".weixinpay").css("display","block"); });
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。