一、业务逻辑
1.续接昨天的,当在getOrderInfo.html页面点击提交订单后,昨天是生成了一个order订单和order_item订单商品(订单明细),在昨天的基础上还要生成一个pay_log支付订单,这个支付订单不仅要保存到数据库中,还要把pay_log这个对象保存在redis中,如果生成订单成功后,跳转支付页面pay.html
2.一跳转到支付页面pay.html,就要生成微信二维码,生成二维码需要两个参数:通过用户id(userId)在redis中获取pay_log对象,进而获取支付订单号out_trade_no和支付金额total_fee这两个参数.
3.拿着这两个参数,就可以在service层通过HttpClient去请求对接微信的接口,请求中传递一个携带商品信息的xml类型的字符串(我们先将需要必要的信息封装到一个map集合中,然后通过提供一个签名信息给微信的工具类将map集合生成一个xml类型的字符串);然后微信端给我们返回来的也是一个xml类型的字符串,我们通过微信的工具类将其转为一个map类型,经过我们重新封装一个map返回给页面,这个封装后的map携带三个参数:返回支付二维码的url,页面要显示的订单号,页面要显示的总金额,代码如下:
/**
* 生成微信二维码
*
* @param out_trade_no 支付单号(一个用户只有一个支付单号,一个支付单号上可以有很多订单号)
* @param total_fee 总金额
* @return
*/
@Override
public Map createNative(String out_trade_no, String total_fee) {
try {
//通过HttpClient来给微信的接口连接发送请求
HttpClientUtil httpClient = new HttpClientUtil("https://api.mch.weixin.qq.com/pay/unifiedorder");
//因为访问微信的接口需要很多必要的参数信息,所以封装成一个map集合
Map requestMap = new HashMap();
requestMap.put("appid", appid);//公众号id
requestMap.put("mch_id", mch_id);//商户号id
requestMap.put("nonce_str", WXPayUtil.generateUUID());//生成一个随机字符串加密用
requestMap.put("body", "品优购商品");//商品描述
requestMap.put("out_trade_no", out_trade_no);//支付单号
requestMap.put("total_fee",total_fee);//总金额(单位:分)
requestMap.put("spbill_create_ip","127.0.0.1");//终端ip(一般是手机上给传过来的)
requestMap.put("notify_url",notifyurl);//通知地址
requestMap.put("trade_type","NATIVE");//交易类型
//将请求参数封装的Map集合转成XML类型的,需要携带签名信息
String requestXML = WXPayUtil.generateSignedXml(requestMap, partnerkey);
//微信只接受XML类型的参数
httpClient.setXmlParam(requestXML);
//因为微信给的接口的连接是https,所以需要设置请求的协议
httpClient.setHttps(true);
//发送请求
httpClient.post();
//接收响应内容(因为微信响应回来的是XML类型的)
String responseXML = httpClient.getContent();
//将XML类型的响应内容转成map类型的
Map responseMap = WXPayUtil.xmlToMap(responseXML);
//将结果重新封装为了去除不要的信息
Map resultMap=new HashMap();
//通过返回结果result_code判断是否成功
if("SUCCESS".equals(responseMap.get("result_code"))){
resultMap.put("code_url",responseMap.get("code_url"));//返回的支付二维码
resultMap.put("out_trade_no",out_trade_no);//为了页面显示订单号
resultMap.put("total_fee",total_fee);//为了页面显示总金额
}
return resultMap;
} catch (Exception e) {
e.printStackTrace();
return new HashMap();
}
}
4.前端部分通过接收一个map集合,获取map集合中的url通过qrious(二维码生成插件)来在页面生成二维码
5.一生成二维码就要去后端查询订单状态,还是去对接微信查询订单的接口,通过发送HttpClient请求给微信的接口,需要前端页面返还一个订单号,响应回一个map,这次不用重新封装,直接返回就行
前端controller部分
重点是后端controller层的业务逻辑
@RequestMapping("/queryPayStatus")
public Result queryPayStatus(String out_trade_no) {
//新建一个返回结果
Result result = null;
//
int count = 1;
while (true) {
//返回包含支付状态trade_state的map
Map map = wxPayService.queryPayStatus(out_trade_no);
//支付出错
if (map == null) {
result = new Result(false, "支付异常");
break;
}
//支付成功
if ("SUCCESS".equals(map.get("trade_state"))) {
result = new Result(true, "支付成功");
//支付成功,修改订单状态
wxPayService.updateOrderStatus(out_trade_no,map.get("transaction_id").toString());
break;
}
//请求超时
if (count >= 6) {
System.out.println("超时======================");
result = new Result(false, "timeout");
break;
}
try {
//等待3s,做一次支付单查询
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//查询支付单次数加一
count++;
}
return result;
}
支付成功后,别忘了修改支付订单payLog和订单order的状态,并且清空支付订单pay_log在redis中的缓存,代码如下