前端
// 根据订单id生成微信支付二维码 asyncData({ params, error }) { return orderApi.createNative(params.pid).then(response => { return { payObj: response.data.data.map } }) },
controller
@Autowired private PayLogService payLogService; //生成微信支付二维码的接口 @GetMapping("/createNative/{orderNo}") public R createNative(@PathVariable String orderNo){ //返回相关的一些信息,包含二维码的地址和其他信息 Map map = payLogService.createNative(orderNo); return R.ok().data("map",map); }
service
@Autowired private OrderService orderService; @Override public Map createNative(String orderNo) { try { //根据订单id查询订单信息 LambdaQueryWrapper<Order> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(Order::getOrderNo,orderNo); Order order = orderService.getOne(lambdaQueryWrapper); //设置参数 HashMap m = new HashMap(); m.put("appid",ConstantUtils.APPID); //partner m.put("mch_id", ConstantUtils.PARTNER); m.put("nonce_str", WXPayUtil.generateNonceStr()); m.put("body", order.getCourseTitle()); m.put("out_trade_no", orderNo); m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("1")).longValue()+""); m.put("spbill_create_ip", "127.0.0.1"); m.put("notify_url", ConstantUtils.NOTIFYURL); m.put("trade_type", "NATIVE"); //2、HTTPClient来根据URL访问第三方接口并且传递参数 HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder"); //client设置参数 client.setXmlParam(WXPayUtil.generateSignedXml(m, ConstantUtils.PARTNERKEY)); client.setHttps(true); client.post(); //3、返回第三方的数据 String xml = client.getContent(); Map<String, String> resultMap = WXPayUtil.xmlToMap(xml); //4、封装返回结果集 Map map = new HashMap<>(); map.put("out_trade_no", orderNo); map.put("course_id", order.getCourseId()); map.put("total_fee", order.getTotalFee()); map.put("result_code", resultMap.get("result_code")); //返回二维码操作码 map.put("code_url", resultMap.get("code_url")); //返回二维码图片地址 //微信支付二维码2小时过期,可采取2小时未支付取消订单 //redisTemplate.opsForValue().set(orderNo, map, 120, TimeUnit.MINUTES); return map; }catch (Exception e){ throw new GuliException(20001,"生成二维码失败"); } }
此时前端会不停的每隔三秒向后端发送用户是否确认支付的请求,并且在axios的response中做校验
mounted() {
// 在页面渲染之后执行 // 每隔三秒,去查询一次支付状态 this.timer1 = setInterval(() => { this.queryPayStatus(this.payObj.out_trade_no) }, 3000) }, methods: { // 查询支付状态的方法 queryPayStatus(out_trade_no) { orderApi.queryPayStatus(out_trade_no).then(response => { console.log(response) if (response.data.success) { // 如果支付成功,清除定时器 clearInterval(this.timer1) this.$message({ type: 'success', message: '支付成功!' }) // 跳转到课程详情页面观看视频 this.$router.push({ path: '/course/' + this.payObj.course_id }) } }) } }
response拦截器,如果返回code是28004则用户为登陆进行登陆跳转,如果code是25000则提示用户未支付等待用户支付,如果code是20000则表名后端校验用户已经付款成功,response拦截器放行,执行用户支付成功友好提示,跳转支付后的course页面
import axios from 'axios' import cookie from 'js-cookie' // 创建axios实例 const service = axios.create({ baseURL: 'http://localhost:9001', // api的base_url timeout: 20000 // 请求超时时间 }) // http request 拦截器 service.interceptors.request.use( config => { // debugger if (cookie.get('guli_token')) { config.headers['token'] = cookie.get('guli_token') } return config }, err => { return Promise.reject(err) }) // http response 拦截器 service.interceptors.response.use( response => { // debugger if (response.data.code === 28004) { console.log('response.data.resultCode是28004') // 返回 错误代码-1 清除ticket信息并跳转到登录页面 // debugger window.location.href = '/login' return } else { if (response.data.code !== 20000) { // 25000:订单支付中,不做任何提示 if (response.data.code !== 25000) { // Message({ // message: response.data.message || 'error', // type: 'error', // duration: 5 * 1000 // }) alert('订单未支付') } } else { return response } } }, error => { return Promise.reject(error.response) // 返回接口返回的错误信息 })
export default service
那么后端是如何进行校验的呢?可以看到当前端发来查询订单状态的订单id时,service业务层会带着订单id向微信支付官方接口发送http请求https://api.mch.weixin.qq.com/pay/orderquery,来获取当前订单的状态信息,订单当前在微信官方的状态信息map如下图