微信扫码支付3-生成支付二维码并支付

一、准备

1、添加微信支付SDK

方式一:

service_trade中添加依赖:

<dependencies>
    <!--微信支付-->
    <dependency>
        <groupId>com.github.wxpay</groupId>
        <artifactId>wxpay-sdk</artifactId>
        <version>0.0.3</version>
    </dependency>
</dependencies>

方式二:
将下载的sdk源码放入service_trade源码目录中
BwG7gx.png

2、配置yml参数

支付账户相关参数:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=3_1

weixin:
  pay:
    #关联的公众号appid
    appId: wxf913bfa3a2c7eeeb
    #商户号
    partner: 1543338551
    #商户key
    partnerKey: atguigu3b0kn9g5v426MKfHQH7X8rKwb
    #回调地址
    notifyUrl: http://imhelen.free.idcfengye.com/api/trade/weixin-pay/callback/notify 

配置后启动ngrok内网穿透工具

3、参数读取工具类

package com.atguigu.guli.service.trade.util;
@Data
@Component
@ConfigurationProperties(prefix="weixin.pay")
public class WeixinPayProperties {
    private String appId;
    private String partner;
    private String partnerKey;
    private String notifyUrl;
}

4、辅助业务方法

OrderService:getOrderByOrderNo 根据订单号查询订单
接口:

Order getOrderByOrderNo(String orderNo);

实现:

public Order getOrderByOrderNo(String orderNo) {

    QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("order_no", orderNo);
    return baseMapper.selectOne(queryWrapper);
}

二、生成支付二维码

1、统一下单接口文档

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1
调用统一下单接口,根据返回值中的code_url在前端使用javascript工具生成支付二维码

2、业务层

接口:创建 WeixinPayService:createNative

package com.atguigu.guli.service.order.service;
public interface WeixinPayService {
    Map<String, Object> createNative(String orderNo, String remoteAddr);
}

实现:

package com.atguigu.guli.service.trade.service.impl;

@Service
@Slf4j
public class WeixinPayServiceImpl implements WeixinPayService {

    @Autowired
    private OrderService orderService;
    
    @Autowired
    private WeixinPayProperties weixinPayProperties;
    
    @Override
    public Map<String, Object> createNative(String orderNo, String remoteAddr) {
        try{
            //根据课程订单号获取订单
            Order order = orderService.getOrderByOrderNo(orderNo);
    
            //调用微信api接口:统一下单(支付订单)
            HttpClientUtils client = new HttpClientUtils("https://api.mch.weixin.qq.com/pay/unifiedorder");
            //组装接口参数
            Map<String, String> params = new HashMap<>();
            params.put("appid", weixinPayProperties.getAppId());//关联的公众号的appid
            params.put("mch_id", weixinPayProperties.getPartner());//商户号
            params.put("nonce_str", WXPayUtil.generateNonceStr());//生成随机字符串
            params.put("body", order.getCourseTitle());
            params.put("out_trade_no", orderNo);
    
            //注意,这里必须使用字符串类型的参数(总金额:分)
            String totalFee = order.getTotalFee().intValue() + "";
            params.put("total_fee", totalFee);
    
            params.put("spbill_create_ip", remoteAddr);
            params.put("notify_url", weixinPayProperties.getNotifyUrl());
            params.put("trade_type", "NATIVE");
    
            //将参数转换成xml字符串格式:生成带有签名的xml格式字符串
            String xmlParams = WXPayUtil.generateSignedXml(params, weixinPayProperties.getPartnerKey());
            log.info("\n xmlParams:\n" + xmlParams);
    
            client.setXmlParam(xmlParams);//将参数放入请求对象的方法体
            client.setHttps(true);//使用https形式发送
            client.post();//发送请求
            String resultXml = client.getContent();//得到响应结果
            log.info("\n resultXml:\n" + resultXml);
            //将xml响应结果转成map对象
            Map<String, String> resultMap = WXPayUtil.xmlToMap(resultXml);
    
            //错误处理
            if("FAIL".equals(resultMap.get("return_code")) || "FAIL".equals(resultMap.get("result_code"))){
                log.error("微信支付统一下单错误 - "
                        + "return_code: " + resultMap.get("return_code")
                        + "return_msg: " + resultMap.get("return_msg")
                        + "result_code: " + resultMap.get("result_code")
                        + "err_code: " + resultMap.get("err_code")
                        + "err_code_des: " + resultMap.get("err_code_des"));
    
                throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
            }
    
            //组装需要的内容
            Map<String, Object> map = new HashMap<>();
            map.put("result_code", resultMap.get("result_code"));//响应码
            map.put("code_url", resultMap.get("code_url"));//生成二维码的url
            map.put("course_id", order.getCourseId());//课程id
            map.put("total_fee", order.getTotalFee());//订单总金额
            map.put("out_trade_no", orderNo);//订单号
    
            return map;
    
        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
        }
    }
}

3、web层

创建 ApiWeixinPayController:createNative

package com.atguigu.guli.service.trade.controller.api;

@RestController
@RequestMapping("/api/trade/weixin-pay")
@Api(description = "网站微信支付")
@CrossOrigin //跨域
@Slf4j
public class ApiWeixinPayController {

    @Autowired
    private WeixinPayService weixinPayService;
    
    @GetMapping("create-native/{orderNo}")
    public R createNative(@PathVariable String orderNo, HttpServletRequest request) {
        String remoteAddr = request.getRemoteAddr();
        Map map = weixinPayService.createNative(orderNo, remoteAddr);
        return R.ok().data(map);
    }
}

三、支付前端

1、安装二维码生成器

npm install vue-qriously@1.1.1

2、配置插件

创建 plugins/vue-qriously-plugin.js

import Vue from 'vue'
import VueQriously from 'vue-qriously'
Vue.use(VueQriously)

nuxt.config.js中配置

plugins: [
    { src: '~/plugins/vue-qriously-plugin.js', ssr: true }
],

3、api

创建 api/pay.js

import request from '~/utils/request'

export default {
  createNative(orderNo) {
    return request({
      baseURL: 'http://localhost:8170',
      url: `/api/trade/weixin-pay/create-native/${orderNo}`,
      method: 'get'
    })
  }
}

4、订单页面

html:

<el-button :disabled="!agree" type="danger" @click="toPay()">去支付</el-button>

脚本:

methods: {
    toPay() {
        if (this.agree) {
            this.$router.push({ path: '/pay/' + this.order.orderNo })
        }
    }
}

5、支付页面

创建pages/pay/_id.vue

<template>
  <div class="cart py-container">
    <!--主内容-->
    <div class="checkout py-container  pay">
      <div class="checkout-tit" style="width: 1050px; margin: 0 auto; padding: 10px 0;">
        <h4 class="fl tit-txt"><span class="success-info">支付申请提交成功,请您及时付款!订单号:{{ payObj.out_trade_no }}</span>
        </h4>
        <span class="fr"><em class="sui-lead">应付金额:</em><em class="orange money">¥{{ payObj.total_fee/100 }}</em></span>
        <div class="clearfix"/>
      </div>
      <div class="checkout-steps">
        <div class="fl weixin">微信支付</div>
        <div class="fl sao">
          <div class="fl code">
            <!-- <img id="qrious" src="~/assets/img/erweima.png" alt=""> -->
            <qriously :value="payObj.code_url" :size="338"/>
          </div>
          <div style="color: red; text-align:center;">请使用微信扫一扫</div>  
        </div>
        <div class="clearfix"/>
        <!-- <p><a href="pay.html" target="_blank"> 其他支付方式</a></p> -->
      </div>
    </div>

  </div>
</template>
<script>
import payApi from '~/api/pay'
export default {
  async asyncData(page) {
    const response = await payApi.createNative(page.route.params.id)
    return {
      payObj: response.data
    }
  }

  // 在created中获取数据,报告Invalid prop: type check failed for prop "value".
  // created() {
  //   payApi.createNative(this.$route.params.id).then(response => {
  //     this.payObj = response.data
  //   })
  // }
}
</script>
posted @ 2020-11-01 15:31  碧水云天4  阅读(1271)  评论(0编辑  收藏  举报