这块的内容比较复杂。在网上找了很多的文章,发现很多都不是能在我做的这个项目中跑起来。最终借助公司大佬的力量才勉强的把这块的内容完成。实属不易。
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_10&index=1
上面的链接是微信小程序开发文档关于微信支付的内容。建议看3遍以上
小程序的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.orderno
that.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.首先是支付的代码:
在刚支付的时候我们就要在会员权益表中增加这一条数据了,不管是否支付成功,因为支付失败那是回调之后的失败。
/**
* 微信内调起支付
*
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/wxPay", method = { RequestMethod.GET, RequestMethod.POST })
@ResponseBody
public Response> wxPay(HttpServletRequest request) {
// 根据请求中的token来获取缓存中的用户信息
Response resp = new Response<>();
Member loginUser = MemberManager.getMember(request);
if (loginUser == null) {
resp.setCode(CommonReturnCode.ERROR.code());
return resp;
}
//前台传过来的数据
String priceid = ServletRequestUtils.getStringParameter(request, "priceid", null);
String latitude = ServletRequestUtils.getStringParameter(request, "payLatitude", null);
String longitude = ServletRequestUtils.getStringParameter(request, "payLongitude", null);
Validator validator = new Validator();
// 获取地址情况 地址错误时不保存地址
validator.required(latitude, "位置获取失败");
validator.required(longitude, "位置获取失败");
validator.number(request, "latitude", "位置获取失败");
validator.number(request, "longitude", "位置获取失败");
ReverseGeocodingResult RGResult = null;
if (!validator.isError()) {
RGResult = BaiduMapApi.getReverseGeocoding(latitude, longitude);
}
MemberPrice memberprice = memberPriceService.selectById(priceid);
// 判断订单是否存在
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String orderNum = "HYQY" + sdf.format(new Date()) + StringRandom.getRandomNum();
BigDecimal amount = memberprice.getPrice();
//把值塞进会员购买会员的表中
MembershipBuyOrder order = 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 = null;
if (RGResult != null) {
plRecord = new PaymentLocation(PaymentLocation.BusinessType.MEMBERSHIP, order.getId(),
RGResult.getFormatted_address(), RGResult.getSematic_description(), RGResult.getAddressComponent(),
RGResult.getLocation());
}
//这些必要的数据是我们表中的数据
String appid = ApplicationConfigurer.getStringProperty("wxMiniprogramAppID", "");
String mch_id = ApplicationConfigurer.getStringProperty("wxMiniprogramAppMchId", "");
String webContext = ApplicationConfigurer.getStringProperty("web.context", "");
String paternerKey = ApplicationConfigurer.getStringProperty("wxpayAppKey", "");
try {
// 组织支付参数信息
Map paraMap = new HashMap();
// 获取请求ip地址
String ip = RequestUtil.getRequestIP(request);
// 下单成功的回调(很重要)
String notifyUrl = webContext + "/wxpay/callOrder/memberCallback.json";
WXPay wxpay = new WXPay(WXMPPayConfigImpl.getInstance(), notifyUrl, true, false);
// 拼接统一下单地址参数
paraMap.put("openid", loginUser.getXcx_openid());
paraMap.put("out_trade_no", orderNum);// 商品的订单号每次要唯一
paraMap.put("fee_type", "CNY");
// 化元为分,化小为整
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 = wxpay.unifiedOrder(paraMap);
// 发送post请求"统一下单接口"返回预支付id:prepay_id
if (!WXPayConstants.SUCCESS.equals(resultMap.get("result_code"))) {
return new Response<>(CommonReturnCode.ERROR, "获取失败,请稍后重试");
}
String prepay_id = resultMap.get("prepay_id");// 预支付id
Map payMap = new HashMap();
payMap.put("appId", appid);
payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
payMap.put("nonceStr", WXPayUtil.generateNonceStr());
payMap.put("signType", "MD5");
payMap.put("package", "prepay_id=" + prepay_id);
String paySign = WXPayUtil.generateSignature(payMap, paternerKey, SignType.HMACSHA256);
payMap.put("paySign", paySign);
boolean result = membershipBuyOrderService.insert(order);
Map responseResultMap = new HashMap<>();
payMap.remove("appId");
responseResultMap.put("payData", payMap);
responseResultMap.put("orderno", order.getOrderno());
if (result) {
if (plRecord != null) {
plRecord.setRecordid(order.getId());
// 保证订单支付地址的唯一性
Wrapper plWrapper = 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方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = 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 = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
/**
* 微信支付账单查询:该接口不做复杂的业务处理,仅根据商户订单号查询订单情况返回支付结果
*
* @param request
* @param response
*/
@RequestMapping(value = "/orderQuery", method = { RequestMethod.POST, RequestMethod.GET })
@ResponseBody
public Response> orderQuery(HttpServletRequest request, HttpServletResponse response) {
String orderno = ServletRequestUtils.getStringParameter(request, "orderno", "");
if (StringUtils.isBlank(orderno)) {
return new Response<>(CommonReturnCode.ERROR, "订单查询失败");
}
try {
WXPay wxpay = new WXPay(WXMPPayConfigImpl.getInstance());
Map data = new HashMap();
data.put("out_trade_no", orderno);
Map resp = wxpay.orderQuery(data);
if (WXPayConstants.SUCCESS.equals(resp.get("result_code"))
&& WXPayConstants.SUCCESS.equals(resp.get("return_code"))) {
Map resultMap = 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.支付回调的方法(很重要)
/**
* 购买会员积分回调
*
* @param request
* @param response
* @return
*/
@RequestMapping(value = "memberCallback", method = { RequestMethod.GET, RequestMethod.POST })
@ResponseBody
public void memberCallback(HttpServletRequest request, HttpServletResponse response) {
BufferedReader br = null;
String xml = " ";
try {
StringBuilder result = new StringBuilder();
br = request.getReader();
for (String line; (line = br.readLine()) != null;) {
if (result.length() > 0) {
result.append("\n");
}
result.append(line);
}
String notifyData = result.toString(); // 支付结果通知的xml格式数据
WXPay wxpay = new WXPay(WXMPPayConfigImpl.getInstance());
Map notifyMap = WXPayUtil.xmlToMap(notifyData); // 转换成map
if (wxpay.isResponseSignatureValid(notifyMap)) {
// 签名正确,处理
// 进行处理
BigDecimal cash_fee = new BigDecimal(notifyMap.get("cash_fee"));
// 根据订单流水号查询会员升级订单
Wrapper wrapper = new EntityWrapper<>();
wrapper.eq("orderno", notifyMap.get("out_trade_no"));
MembershipBuyOrder record = membershipBuyOrderService.selectOne(wrapper);
// 比对支付金额是否正确和支付状态
if (cash_fee.compareTo(record.getAmount().multiply(new BigDecimal(100))) == 0
&& record.getStatus() == OrderEnums.Status.TODO.getValue()) {
Member member = memberService.selectById(record.getMemberid());
//处理复杂的各种表的逻辑
if (flag) {
xml = " ";
}
}
} else {
// 签名错误,如果数据里没有sign字段,也认为是签名错误
}
response.getWriter().write(xml);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}