微信小程序 微信支付 + Java后台接口
这块的内容比较复杂。在网上找了很多的文章,发现很多都不是能在我做的这个项目中跑起来。最终借助公司大佬的力量才勉强的把这块的内容完成。实属不易。
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_10&index=1
上面的链接是微信小程序开发文档关于微信支付的内容。建议看3遍以上
在微信支付之前必须要有下面5样材料
小程序的appid,APPsecret,支付商户号(mch_id),商户密钥(key),付款用户的openid
申请接入微信商户地址:https://pay.weixin.qq.com/static/applyment_guide/applyment_detail_miniapp.shtml
接下来就要贴代码了,首先是小程序端的代码:
//支付方法purchaseMember: function purchaseMember() {wx.showLoading({ title: '正在加载', mask: true });var that = this;var index = that.data.currentIndex;var priceInfo = that.data.priceObj;_utils2.default.requestPayment({url: '/webapi/pay/wxPay.json',data: { priceid: priceInfo[index].id },fail: function fail(res) {wx.showToast({ title: '支付取消', icon: 'none' });},success: function success(res) {wx.showToast({ title: '支付成功' });that.setData({ showGetMemberPopup: false });// 查询支付结果,支付成功后刷新用户缓存that.orderQuery();},callback: function callback(resultData) {wx.hideLoading();// that.data.orderno = resultData.ordernothat.data.orderno = resultData.orderno;}});},orderQuery: function orderQuery() {wx.showLoading({ title: '正在加载', mask: true });var that = this;getApp().GET({ url: "/webapi/pay/orderQuery.json",data: { orderno: that.data.orderno },success: function success(res) {wx.hideLoading();if (res.success && res.data.state == 'SUCCESS') {that.refresh();} else {wx.showToast({ title: res.msg, icon: 'none' });}}});},
统一下单的地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
这里面的参数很重要,要好好比对,必要的参数一定要有
Java后台代码相当多:
1.首先是支付的代码:
在刚支付的时候我们就要在会员权益表中增加这一条数据了,不管是否支付成功,因为支付失败那是回调之后的失败。
/*** 微信内调起支付* * &#64;param request* &#64;param response* &#64;return*/&#64;RequestMapping(value &#61; "/wxPay", method &#61; { RequestMethod.GET, RequestMethod.POST })&#64;ResponseBodypublic Response> wxPay(HttpServletRequest request) {// 根据请求中的token来获取缓存中的用户信息Response resp &#61; new Response<>();Member loginUser &#61; MemberManager.getMember(request);if (loginUser &#61;&#61; null) {resp.setCode(CommonReturnCode.ERROR.code());return resp;}//前台传过来的数据String priceid &#61; ServletRequestUtils.getStringParameter(request, "priceid", null);String latitude &#61; ServletRequestUtils.getStringParameter(request, "payLatitude", null);String longitude &#61; ServletRequestUtils.getStringParameter(request, "payLongitude", null);Validator validator &#61; new Validator();// 获取地址情况 地址错误时不保存地址validator.required(latitude, "位置获取失败");validator.required(longitude, "位置获取失败");validator.number(request, "latitude", "位置获取失败");validator.number(request, "longitude", "位置获取失败");ReverseGeocodingResult RGResult &#61; null;if (!validator.isError()) {RGResult &#61; BaiduMapApi.getReverseGeocoding(latitude, longitude);}MemberPrice memberprice &#61; memberPriceService.selectById(priceid);// 判断订单是否存在SimpleDateFormat sdf &#61; new SimpleDateFormat("yyyyMMddHHmmss");String orderNum &#61; "HYQY" &#43; sdf.format(new Date()) &#43; StringRandom.getRandomNum();BigDecimal amount &#61; memberprice.getPrice();//把值塞进会员购买会员的表中MembershipBuyOrder order &#61; new MembershipBuyOrder();order.setMemberid(loginUser.getId());order.setPriceid(priceid);order.setPricename(memberprice.getName());order.setDuration(memberprice.getDuration());order.setTimeunit(Integer.valueOf(memberprice.getTimeunit()));order.setAmount(amount);order.setPaytype(OrderEnums.PayType.MONEY.getValue());order.setOrderno(orderNum);order.setStatus(1);order.setCreatetime(DateUtils.dateTimeToString(new Date()));PaymentLocation plRecord &#61; null;if (RGResult !&#61; null) {plRecord &#61; new PaymentLocation(PaymentLocation.BusinessType.MEMBERSHIP, order.getId(),RGResult.getFormatted_address(), RGResult.getSematic_description(), RGResult.getAddressComponent(),RGResult.getLocation());}//这些必要的数据是我们表中的数据String appid &#61; ApplicationConfigurer.getStringProperty("wxMiniprogramAppID", "");String mch_id &#61; ApplicationConfigurer.getStringProperty("wxMiniprogramAppMchId", "");String webContext &#61; ApplicationConfigurer.getStringProperty("web.context", "");String paternerKey &#61; ApplicationConfigurer.getStringProperty("wxpayAppKey", "");try {// 组织支付参数信息Map paraMap &#61; new HashMap();// 获取请求ip地址String ip &#61; RequestUtil.getRequestIP(request);// 下单成功的回调&#xff08;很重要&#xff09;String notifyUrl &#61; webContext &#43; "/wxpay/callOrder/memberCallback.json";WXPay wxpay &#61; new WXPay(WXMPPayConfigImpl.getInstance(), notifyUrl, true, false);// 拼接统一下单地址参数paraMap.put("openid", loginUser.getXcx_openid());paraMap.put("out_trade_no", orderNum);// 商品的订单号每次要唯一paraMap.put("fee_type", "CNY");// 化元为分&#xff0c;化小为整paraMap.put("total_fee", String.valueOf(amount.multiply(new BigDecimal(100)).longValue()));paraMap.put("mch_id", mch_id);paraMap.put("spbill_create_ip", ip);// 此路径是微信服务器调用支付结果通知路径paraMap.put("trade_type", "JSAPI");paraMap.put("body", "会员权益购买会员");paraMap.put("notify_url", notifyUrl);// 使用 wxpayAppKey 请求体 生成签名Map resultMap &#61; wxpay.unifiedOrder(paraMap);// 发送post请求"统一下单接口"返回预支付id:prepay_idif (!WXPayConstants.SUCCESS.equals(resultMap.get("result_code"))) {return new Response<>(CommonReturnCode.ERROR, "获取失败&#xff0c;请稍后重试");}String prepay_id &#61; resultMap.get("prepay_id");// 预支付idMap payMap &#61; new HashMap();payMap.put("appId", appid);payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() &#43; "");payMap.put("nonceStr", WXPayUtil.generateNonceStr());payMap.put("signType", "MD5");payMap.put("package", "prepay_id&#61;" &#43; prepay_id);String paySign &#61; WXPayUtil.generateSignature(payMap, paternerKey, SignType.HMACSHA256);payMap.put("paySign", paySign);boolean result &#61; membershipBuyOrderService.insert(order);Map responseResultMap &#61; new HashMap<>();payMap.remove("appId");responseResultMap.put("payData", payMap);responseResultMap.put("orderno", order.getOrderno());if (result) {if (plRecord !&#61; null) {plRecord.setRecordid(order.getId());// 保证订单支付地址的唯一性Wrapper plWrapper &#61; new EntityWrapper<>();plWrapper.eq("recordid", plRecord.getRecordid()).eq("businesstype", plRecord.getBusinesstype());paymentLocationService.delete(plWrapper);paymentLocationService.insert(plRecord);}return new Response<>(responseResultMap);} else {return new Response<>(CommonReturnCode.ERROR, "购买会员失败");}} catch (Exception e) {e.printStackTrace();}return new Response<>(CommonReturnCode.ERROR, "购买会员失败");}
/*** 向指定 URL 发送POST方法的请求* * &#64;param url* 发送请求的 URL* &#64;param param* 请求参数,请求参数应该是 name1&#61;value1&name2&#61;value2 的形式。* &#64;return 所代表远程资源的响应结果*/public static String sendPost(String url, String param) {PrintWriter out &#61; null;BufferedReader in &#61; null;String result &#61; "";try {URL realUrl &#61; new URL(url);// 打开和URL之间的连接URLConnection conn &#61; realUrl.openConnection();// 设置通用的请求属性conn.setRequestProperty("accept", "*/*");conn.setRequestProperty("connection", "Keep-Alive");conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");// 发送POST请求必须设置如下两行conn.setDoOutput(true);conn.setDoInput(true);// 获取URLConnection对象对应的输出流out &#61; new PrintWriter(conn.getOutputStream());// 发送请求参数out.print(param);// flush输出流的缓冲out.flush();// 定义BufferedReader输入流来读取URL的响应in &#61; new BufferedReader(new InputStreamReader(conn.getInputStream()));String line;while ((line &#61; in.readLine()) !&#61; null) {result &#43;&#61; line;}} catch (Exception e) {System.out.println("发送 POST 请求出现异常&#xff01;" &#43; e);e.printStackTrace();}// 使用finally块来关闭输出流、输入流finally {try {if (out !&#61; null) {out.close();}if (in !&#61; null) {in.close();}} catch (IOException ex) {ex.printStackTrace();}}return result;}
/*** 微信支付账单查询&#xff1a;该接口不做复杂的业务处理&#xff0c;仅根据商户订单号查询订单情况返回支付结果* * &#64;param request* &#64;param response*/&#64;RequestMapping(value &#61; "/orderQuery", method &#61; { RequestMethod.POST, RequestMethod.GET })&#64;ResponseBodypublic Response> orderQuery(HttpServletRequest request, HttpServletResponse response) {String orderno &#61; ServletRequestUtils.getStringParameter(request, "orderno", "");if (StringUtils.isBlank(orderno)) {return new Response<>(CommonReturnCode.ERROR, "订单查询失败");}try {WXPay wxpay &#61; new WXPay(WXMPPayConfigImpl.getInstance());Map data &#61; new HashMap();data.put("out_trade_no", orderno);Map resp &#61; wxpay.orderQuery(data);if (WXPayConstants.SUCCESS.equals(resp.get("result_code"))&& WXPayConstants.SUCCESS.equals(resp.get("return_code"))) {Map resultMap &#61; new HashMap();resultMap.put("state", resp.get("trade_state"));resultMap.put("desc", resp.get("trade_state_desc"));return new Response<>(resultMap);}} catch (Exception e) {e.printStackTrace();}return new Response<>(CommonReturnCode.ERROR, "订单支付失败");}
2.支付回调的方法&#xff08;很重要&#xff09;
/*** 购买会员积分回调* * &#64;param request* &#64;param response* &#64;return*/&#64;RequestMapping(value &#61; "memberCallback", method &#61; { RequestMethod.GET, RequestMethod.POST })&#64;ResponseBodypublic void memberCallback(HttpServletRequest request, HttpServletResponse response) {BufferedReader br &#61; null;String xml &#61; "";try {StringBuilder result &#61; new StringBuilder();br &#61; request.getReader();for (String line; (line &#61; br.readLine()) !&#61; null;) {if (result.length() > 0) {result.append("\n");}result.append(line);}String notifyData &#61; result.toString(); // 支付结果通知的xml格式数据WXPay wxpay &#61; new WXPay(WXMPPayConfigImpl.getInstance());Map notifyMap &#61; WXPayUtil.xmlToMap(notifyData); // 转换成mapif (wxpay.isResponseSignatureValid(notifyMap)) {// 签名正确&#xff0c;处理// 进行处理BigDecimal cash_fee &#61; new BigDecimal(notifyMap.get("cash_fee"));// 根据订单流水号查询会员升级订单Wrapper wrapper &#61; new EntityWrapper<>();wrapper.eq("orderno", notifyMap.get("out_trade_no"));MembershipBuyOrder record &#61; membershipBuyOrderService.selectOne(wrapper);// 比对支付金额是否正确和支付状态if (cash_fee.compareTo(record.getAmount().multiply(new BigDecimal(100))) &#61;&#61; 0&& record.getStatus() &#61;&#61; OrderEnums.Status.TODO.getValue()) {Member member &#61; memberService.selectById(record.getMemberid());//处理复杂的各种表的逻辑if (flag) {xml &#61; "";}}} else {// 签名错误&#xff0c;如果数据里没有sign字段&#xff0c;也认为是签名错误}response.getWriter().write(xml);} catch (Exception e) {e.printStackTrace();} finally {if (br !&#61; null) {try {br.close();} catch (IOException e) {e.printStackTrace();}}}}
再调用的话就可以了 总结就是回调的方法真的非常重要&#xff01;&#xff01;&#xff01;