JAVA微信小程序支付源码

mac2024-06-04  38

做了很多次都没整理,总以为脑子记住了,可当下次用的时候又跟个脑瘫孩儿一样,今天就记录一下部分代码。需要帮助加QQ 1137586868

首先解释一下微信的签名制作方式:这里可能让小白最头疼的了,统一下单和支付时要的签名制作方式也都不一样。我这里只打个比喻让你理解怎么制作,具体的代码里已经有了。 比如说你要给统一下单接口发送请求参数 A B C D E F(其中F代表的你签名),ABCDE都是固定的参数,如appId,时间戳等, 那F怎么得来呢? 其实就是 A+B+C+D+E 以后,在通过MD5编译,形成的结果就是很长的字符串,在把字符串转为大写就做成了你的签名F。

总的来说,其实就3步。

1发起统一下单接口

统一下单接口是由java来搞得,但 通常情况下,由用户在小程序点击支付按钮触发,所以需要在小程序部分先发起请求,把自己业务的数据传到后台,在进行统一下单。

// 立即购买 justBuy: function () { var that = this wx.request({ url: app.globalData.PROJECTPATH + '/task/saveSalarGoods.htm', data: { userId: app.globalData.userId,//自己的用户ID openid: app.globalData.openid,//小程序用户的ID, goodsId: that.data.result.id,//自己商品ID name: that.data.addressArr[0].name,//自己的 phone: that.data.addressArr[0].phone,//自己的 address: that.data.addressArr[0].address,//自己的 addressDetail: that.data.addressArr[0].addressDetail//自己的 }, success: function (res) { //统一订单接口执行完成后,由小程序发起支付,调用wx.requestPayment方法,这个方法在第二步介绍 } } }) }

下面是java的统一下单代码

/** * 购买商品统一下单接口 * @throws UnsupportedEncodingException */ @RequestMapping("saveSalarGoods.htm") public void salasGoods(String name,String phone,String address,String addressDetail,String openid,String goodsId,String userId,HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException{ if (StringUtils.isBlank(userId)) { printStrAjax(response, HttpUtil.getClientResult(-1, "传递参数错误", null)); return; } YpSales ypgoods = ypSalesService.selectById(goodsId); if (ypgoods.getGoods_status() == 2 || ypgoods.getGoods_status() == 3 ) { printStrAjax(response, HttpUtil.getClientResult(-1, "该商品已出售,请刷新页面获取最新数据", null)); return; } ypgoods.setAddress_user(new String(name.getBytes("ISO-8859-1"), "UTF-8")); ypgoods.setAddress_phone(phone); ypgoods.setAddress(new String(address.getBytes("ISO-8859-1"), "UTF-8")); ypgoods.setAddress_detail(new String(addressDetail.getBytes("ISO-8859-1"), "UTF-8")); ypSalesService.saveSales(ypgoods); String amount = String.valueOf(ypgoods.getGoods_money()*Constants.MOENY_PRPORTION); String payId = payService.savePay(goodsId, userId, Integer.parseInt(amount), 4); //上面的都是我的业务代码,下面开始进行统一下单接口前得准备工作 //创建hashmap(用户获得签名) SortedMap<String, String> paraMap = new TreeMap<String, String>(); //设置body变量 (支付成功显示在微信支付 商品详情中) String body = "LHGS-PAY-GOODS"; //设置随机字符串 String nonceStr = PayUtil.createCode(32); //设置请求参数(小程序ID) paraMap.put("appid", Constants.appID); //设置请求参数(商户号) paraMap.put("mch_id", Constants.MCH_ID); //设置请求参数(随机字符串) paraMap.put("nonce_str", nonceStr); //设置请求参数(商品描述) paraMap.put("body", PayUtil.urlEncodeUTF8(body)); //设置请求参数(商户订单号) paraMap.put("out_trade_no", payId); //设置请求参数(总金额) paraMap.put("total_fee", amount); //设置请求参数(终端IP) paraMap.put("spbill_create_ip", "127.0.0.1"); //设置请求参数(回调通知地址) paraMap.put("notify_url", Constants.SALES_PAY_PATH); //设置请求参数(交易类型) paraMap.put("trade_type", "JSAPI"); //设置请求参数(openid)(在接口文档中 该参数 是否必填项 但是一定要注意 如果交易类型设置成'JSAPI'则必须传入openid) paraMap.put("openid", openid); //自定义参数(我放的流水ID,用于回调的时候修改状态) paraMap.put("device_info", payId); String stringA = PayUtil.createLinkString(paraMap); //第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。(签名) String sign = PayUtil.sign(stringA, Constants.key, "utf-8").toUpperCase(); //将参数 编写XML格式 paraMap.put("sign",sign); String s = null; s = PayUtil.GetMapToXML(paraMap); Map map = null; try { map = PayUtil.doXMLParse(PayUtil.httpRequest(Constants.UNIFIED_ORDER_PATH,s)); } catch (Exception e) { printStrAjax(response, HttpUtil.getClientResult(-1, "统一下单接口执行失败", map)); return; } if (!map.get("return_code").equals("SUCCESS")) { printStrAjax(response, HttpUtil.getClientResult(-1, "统一下单接口执行失败", map)); return; } /** * 统一下单接口执行成功,即map中返回值return_code=SUCCESS时。 * 制作支付的请求参数,和签名, */ SortedMap<String, String> paraMapPay = new TreeMap<String, String>(); String timeStampPay = Long.toString(System.currentTimeMillis() / 1000); String nonceStrPay = PayUtil.createCode(32); String packagePay = (String) map.get("prepay_id");//请求统一下单成功时,获取这个参数,调起支付时要传递 String signTypePay ="MD5"; paraMapPay.put("timeStamp", timeStampPay); paraMapPay.put("nonceStr", nonceStrPay); paraMapPay.put("package", "prepay_id="+packagePay); paraMapPay.put("signType", signTypePay); paraMapPay.put("appId", Constants.appID); String payString = PayUtil.createLinkString(paraMapPay); String signPay = PayUtil.sign(payString, Constants.key, "utf-8").toUpperCase(); String paySignPay = signPay; //这是传递给小程序的支付所需要的参数。 Map<String, String> mapPay = new HashMap<String, String>(); mapPay.put("timeStampPay", timeStampPay); mapPay.put("nonceStrPay", nonceStrPay); mapPay.put("packagePay", "prepay_id="+packagePay);//传递时=号不要忘记 mapPay.put("signTypePay", signTypePay); mapPay.put("paySignPay", paySignPay); printStrAjax(response, HttpUtil.getClientResult(1, "统一下单接口执行成功", mapPay)); }

以上代码,已经完成统一下单和支付前得准备工作。

2进行支付

当统一下单返回成功时,并且已经把调起支付的请求参数准备好了,那么直接调用wx.requestPayment。改方法可以写在统一下单请求的返回里面,参考第一步。 切记下面的参数都是JAVA后台制作好传递过来的。

wx.requestPayment( { 'timeStamp': res.data.result.timeStampPay, 'nonceStr': res.data.result.nonceStrPay, 'package': res.data.result.packagePay, 'signType': 'MD5', 'paySign': res.data.result.paySignPay, 'success': function (res) { console.info("微信支付成功"); wx.redirectTo({//这里的成功不代表真的成功,微信文档上说的,具体要看支付回调通知,在java代码里。 url: "../status/status?desc=支付成功&price=" + that.data.myMoney + "元&status=success&title=支付成功" }) }, 'fail': function (res) { console.info("掉起支付失败"); wx.redirectTo({ url: "../status/status?desc=支付失败&status=fail&title=支付失败" }) }, 'complete': function (res) { console.info(""); } })

3支付回调 上面支付成功后,就比较简单了,微信会给你发很多次支付是否成功的请求,你必须得给人家回一个“知道了”, 他才停止。 这个请求需要你在微信小程序里面配置,并且在java代码中,支付的时候也要传递。

这里需要注意的是自己的业务,因为微信发很多次回调,当你接收了以后,你首先更改你订单的支付状态,其次加减库存,所以,在加减库存等操作的时候,可不要随着微信给你请求次数不断的叠加,一定要判断哦。

* 销售商品金额支付后的回调函数 * @param code * @param request * @param response */ @RequestMapping("salesnotify.htm") public void salesnotify(HttpServletRequest request,HttpServletResponse response){ try{ logger.info("info已经入支付成功返回接口--销售"); BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream())); String line = null; StringBuilder sb = new StringBuilder(); while((line = br.readLine()) != null){ sb.append(line); } br.close(); //sb为微信返回的xml String notityXml = sb.toString(); String resXml = ""; System.out.println("---------------接收到的报文------------:" + notityXml); Map map = PayUtil.doXMLParse(notityXml); System.out.println("---------------转换MAP正常------------:"); String returnCode = (String) map.get("return_code"); if("SUCCESS".equals(returnCode)){ logger.info("---------------支付成功已进入------------"); //验证签名是否正确 Map<String, String> validParams = PayUtil.paraFilter(map); //回调验签时需要去除sign和空值参数 String validStr = PayUtil.createLinkString(validParams);//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 String sign = PayUtil.sign(validStr, Constants.key, "utf-8").toUpperCase();//拼装生成服务器端验证的签名 // 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了 System.out.println("---------------组装签名已经完成------------:"); //根据微信官网的介绍,此处不仅对回调的参数进行验签,还需要对返回的金额与系统订单的金额进行比对等 if(sign.equals(map.get("sign"))){ System.out.println("---------------签名正常------------"); /**此处添加自己的业务逻辑代码start**/ String payId = (String) map.get("device_info");//获取我的自定义刺激参数 if (StringUtils.isNotBlank(payId)) { ypSalesService.updateNotify(payId); } /**此处添加自己的业务逻辑代码end**/ //通知微信服务器已经支付成功 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> "; } else { System.out.println("---------------微信支付回调失败!签名不一致------------"); } }else{ System.out.println("---------------支付失败------------"); resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> "; } System.out.println(resXml); System.out.println("微信支付回调数据结束"); BufferedOutputStream out = new BufferedOutputStream( response.getOutputStream()); out.write(resXml.getBytes()); out.flush(); out.close(); logger.info("---------------已反馈给微信------------"); } catch (Exception e) { logger.info("---------------进入异常------------"); } }

直接复制使用的话,很多方法找不到,可以加我Q 1137586868

后面再发一篇退款的代码

最新回复(0)