前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dubbo 分布式架构搭建教育 PC 站 - 微信支付

Dubbo 分布式架构搭建教育 PC 站 - 微信支付

作者头像
RendaZhang
发布2020-11-04 15:23:19
6640
发布2020-11-04 15:23:19
举报
文章被收录于专栏:RendaRenda

创建二维码

安装 qrcodejs2 (注意:安装的是 qrcodejs2,不要安装 qrcode,否则会报错)

代码语言:javascript
复制
npm install  qrcodejs2 --save

页面中引入

代码语言:javascript
复制
<el-dialog :visible.sync="dialogFormVisible" style="width:800px;margin:0px 
auto;" >
  <h1 style="font-size:30px;color:#00B38A">微信扫一扫支付</h1>
  <div id="qrcode" style="width:210px;margin:20px auto;"></div>
</el-dialog>
<script>
import QRCode from 'qrcodejs2'; // 引入qrcodejs
export default {
  name: "Index",
  components: {
    Header,
    Footer,
    // 声明组件
    QRCode
  },
  data() {
    return {
      // 是否显示登录框,true:显示,false:隐藏
      dialogFormVisible: false,
    };
  },
  methods: {
    // 购买课程
    buy(courseid) {
      // alert("购买第【" + courseid + "】门课程成功,加油!");
      // 显示提示框
      this.dialogFormVisible = true;
      // 待 dom 更新之后再用二维码渲染其内容
      this.$nextTick(function(){
          // 直接调用会报错:TypeError: Cannot read property 'appendChild' of null
          this.createCode();
      });
    },
    // 生成二维码
    createCode(){
      // QRCode 存放二维码的 dom 元素 id,二维码的属性参数
      let qrcode = new QRCode('qrcode',{
         // 二维码的宽度
         width:200,
         // 二维码的高度
         height:200,
         // 二维码中包含的信息
         text:"我爱你"
      });
    },
  },
};
</script>

准备工作

名词介绍
  • appid - 微信公众帐号或开放平台 APP 的唯一标识
  • partner - 商户号(配置文件中的 partner:账户)
  • partnerkey - 商户密钥(密码)
  • sign - 数字签名,根据微信官方提供的密钥和一套算法生成的一个加密信息,就是为了保证交易安全

需要注册认证公众号来获取这些信息,费用 300 元 / 次。

获取认证的流程
1) 注册公众号 - 类型:服务号

根据营业执照类型选择以下主体注册:个体工商户 | 企业/公司 | 政府 | 媒体 | 其他类型。

2) 认证公众号

公众号认证后才申请微信支付:300 元 / 次。

3) 提交材料申请微信支付

登录公众平台,左侧菜单【微信支付】,开始填写资料(营业执照)等待审核,审核时间 1~5 工作日。

4) 开户成功,登录商户平台进行验证

资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。

5) 在线签署协议

本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。

6) 查看自己的公众号的参数

lagou-edu-web

commons.PayConfig

代码语言:javascript
复制
package commons;

/**
 * 微信支付商户的配置类
 *
 * @author Renda Zhang
 * @since 2020-10-27 0:43
 */
public class PayConfig {

    // 企业公众号 ID
    public static String appid = "wx8397f8696b538317";
    // 财付通平台的商户帐号
    public static String partner = "1473426802";
    // 财付通平台的商户密钥
    public static String partnerKey = "8A627A4578ACE384017C997F12D68B23";
    // 回调 URL
    public static String notifyurl = "http://a31ef7db.ngrok.io/WeChatPay/WeChatPayNotify";

}

支付流程

代码语言:javascript
复制
用户 -> 打开页面 -> 点击购买 -> 传递商品 id 和价格 -> createCodeController -> 获得价格并搭配商户信息发送给微信进行下单 -> 微信支付系统

微信支付系统 -> 返回支付链接 -> createCodeController -> 返回支付链接 -> 创建支付二维码 -> 用户

用户扫描支付 -> 检查支付状态 —> 传递订单号 —> checkOrderStatusController -> 获得订单号并搭配商户信息发送给微信进行查询订单状态 -> 微信支付系统

微信支付系统 -> 返回支付状态 -> checkOrderStatusController -> 返回支付状态 -> 更新页面信息

工具介绍

微信支付 SDK

微信支付官网下载 SDK:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1

代码语言:javascript
复制
<dependency>
    <groupId>com.github.wxpay</groupId>
    <artifactId>wxpay-sdk</artifactId>
    <version>0.0.3</version>
</dependency>

主要使用 SDK 中的三个功能:

1、获取随机字符串(生成订单编号)。

代码语言:javascript
复制
WXPayUtil.generateNonceStr();

2、将 map 转换成 xml 字符串(自动添加签名)。

代码语言:javascript
复制
WXPayUtil.generateSignedXml(map,partnerKey);

3、将 xml 字符串转换整 map。

代码语言:javascript
复制
WXPayUtil.xmlToMap(result);
`JFinal` 框架

JFinal 是基于 Java 语言的极速 web 开发框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展。

JFinal 取代 HttpClient

代码语言:javascript
复制
<dependency>
    <groupId>com.jfinal</groupId>
    <artifactId>jfinal</artifactId>
    <version>3.5</version>
</dependency>

构建二维码

src\components\Course.vue

代码语言:javascript
复制
<script>
//  生成二维码
    createCode () {
      this.axios
        .get("http://localhost:80/order/createCode", {
          params: {
            // 课程编号
            courseid: this.course.id,
            // 课程名称
            courseid: this.course.courseName,
            // 优惠价,非原价
            price: this.course.discounts,
          },
        })
        .then((result) => {
          console.log(result);
          let qrcode = new QRCode('qrcode',{
            width:200,
            height:200,
            // 将支付连接嵌入到二维码中
            text:result.data.code_url
          });
        })
        .catch((error) => {
          this.$message.error("二维码生成失败!");
        });
    }
</script>

lagou-edu-web 支付配置 commons.PayConfig (上文已配置)

控制层创建二维码 com.renda.wx.WxPayController

代码语言:javascript
复制
package com.renda.wx;

import com.github.wxpay.sdk.WXPayUtil;
import com.jfinal.kit.HttpKit;
import commons.PayConfig;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Renda Zhang
 * @since 2020-10-27 0:41
 */
@RestController
@RequestMapping("order")
public class WxPayController {

    @GetMapping("createCode")
    public Object createCode(String courseid, String coursename, String price) throws Exception {
        coursename = new String(coursename.getBytes("ISO-8859-1"), "UTF-8");
        Map<String, String> mm = new HashMap();
        // 公众账号 ID
        mm.put("appid", PayConfig.appid);
        // 商户号
        mm.put("mch_id", PayConfig.partner);
        // 随机字符串
        mm.put("nonce_str", WXPayUtil.generateNonceStr());
        // 商品简单描述
        mm.put("body", coursename);
        // 随机生成的商户订单号
        mm.put("out_trade_no", WXPayUtil.generateNonceStr());
        // 订单金额,订单总金额,单位为分,只能为整数
        mm.put("total_fee", price);
        // 终端 IP
        mm.put("spbill_create_ip", "127.0.0.1");
        // 通知地址
        mm.put("notify_url", PayConfig.notifyurl);
        // 交易类型
        mm.put("trade_type", "NATIVE");
        // System.out.println("商户信息:" + mm) ;

        // 2.生成数字签名,并发商户信息转换成 xml 格式
        String xml = WXPayUtil.generateSignedXml(mm, PayConfig.partnerKey);
        // System.out.println("商户的 xml 信息:" + xml);

        // 3.将 xml 数据发送给为微信支付平台,从而生成订单
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        // 发送请求,并返回一个 xml 格式的字符串
        String result = HttpKit.post(url, xml);

        // 4.微信支付平台返回 xml 格式数据,将其转换成 map 格式并返回给前端
        Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
        resultMap.put("orderId", mm.get("out_trade_no"));
        return resultMap;
    }

}

检查支付状态

src\components\Course.vue

代码语言:javascript
复制
<!-- 微信支付二维码-->
<el-dialog :visible.sync="dialogFormVisible" style="width:800px;margin:0px 
auto;" >
  <h1 style="font-size:30px;color:#00B38A" >微信扫一扫支付</h1>
  <div id="qrcode" style="width:210px;margin:20px auto;"></div>
  <h2 id="statusText"></h2>
  <p id="timeClose"></p>
</el-dialog>
<script>
data() {
    return {
      // 定时器
      time:null
    };
},
// 生成二维码
createCode(){
  // 去获取支付连接
  this.axios
    .get("http://localhost:80/order/createCode",{
      params:{
        courseid: this.course.id,
        coursename: this.course.courseName,
        price:this.course.discounts,
      }
    })
    .then((result) => {
        console.log("订单号1:"+result.data.out_trade_no);
        // QRCode 存放二维码的 dom 元素 id,二维码的属性参数
        let qrcode = new QRCode('qrcode',{
           width:200,
           height:200,
           // 将返回的数据嵌入到二维码中
           text:result.data.code_url
       });
       // 检查订单状态
       this.axios
          .get("http://localhost:80/order/checkOrderStatus",{
            params:{
              orderId: this.orderId
            }
          })
          .then((result) => {
              console.log(result);
              if(result.data.trade_state=="SUCCESS"){
     document.getElementById("statusText").innerHTML = "<i style='color:#00B38A' class='el-icon-success'></i> 支付成功!";
                  let s = 3;
                  this.closeQRForm(s);
              }
          })
          .catch( (error)=>{
              this.$message.error("查询订单状态失败!");
          });
    })
    .catch( (error)=>{
      this.$message.error("生成二维码失败!");
    });
},
// 倒计时关闭二维码窗口
closeQRForm(s){
  let that = this;
  that.time= setInterval(function(){
      document.getElementById("timeClose").innerHTML = "("+ s-- +") 秒后关闭本窗口!";
      if(s == 0){
        // 停止计时
        clearInterval(that.time);
        // 关闭
        that.dialogFormVisible = false;
        // 解锁购买状态
        that.isBuy = true;
      }
  },1000);
},
</script>

com.renda.wx.WxPayController

代码语言:javascript
复制
package com.renda.wx;

import com.github.wxpay.sdk.WXPayUtil;
import com.jfinal.kit.HttpKit;
import commons.PayConfig;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Renda Zhang
 * @since 2020-10-27 0:41
 */
@RestController
@RequestMapping("order")
public class WxPayController {

    ...

    @GetMapping("checkOrderStatus")
    public Object checkOrderStatus(String orderId) throws Exception {
        // 1.编写商户信息
        Map<String, String> mm = new HashMap();
        // 公众账号 ID
        mm.put("appid", PayConfig.appid);
        // 商户号
        mm.put("mch_id", PayConfig.partner);
        // 商户订单号
        mm.put("out_trade_no", orderId);
        // 随机字符串
        mm.put("nonce_str", WXPayUtil.generateNonceStr());
        // 2.生成数字签名
        String xml = WXPayUtil.generateSignedXml(mm, PayConfig.partnerKey);
        // 3.发送查询请求给微信支付平台
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";

        // 查询订单状态的开始时间点
        long beginTime = System.currentTimeMillis();
        // 不停的去微信支付平台询问是否支付成功
        while (true) {
            // 4.对微信支付平台返回的查询结果进行处理
            String result = HttpKit.post(url, xml);
            Map<String, String> resultMap = WXPayUtil.xmlToMap(result);

            // 已经支付成功,不再询问
            if (resultMap.get("trade_state").equalsIgnoreCase("SUCCESS")) {
                return resultMap;
            }

            // 超过 30 秒未支付,停止询问
            if (System.currentTimeMillis() - beginTime > ) {
                return resultMap;
            }
            // 每隔 3 秒,询问一次微信支付平台
            Thread.sleep();
        }
    }

}

保存订单并更新状态

src\components\Course.vue

代码语言:javascript
复制
// 检查支付状态
this.axios
 .get("http://localhost:80/order/checkOrderStatus",{
  params:{
    // 传递 订单编号 进行查询
    orderId: result.data.orderId
  }
})
.then((result) => {
  if(result.data.trade_state=="SUCCESS"){
    document.getElementById("statusText").innerHTML = "<i style='color:#00B38A' class='el-icon-success'></i> 支付成功!";
    // 支付成功
    this.updateOrder();
  }
  /*
  else if(result.data.trade_state=="NOTPAY"){
    document.getElementById("statusText").innerHTML = "<i style='color:#00B38A' class='el-icon-success'></i> 未支付!";
    this.updateOrder(10);
  }
  */
  // 3 秒后关闭二维码窗口
  let s = ;
  this.closeQRForm(s);
})
.catch( (error)=>{
  this.$message.error("查询订单失败!");
});
// 更新订单的状态
updateOrder(statusCode){
  return this.axios
    .get("http://localhost:80/order/updateOrder",{
      params:{
        orderNo:this.orderNo,
        status:statusCode,
      }
    })
    .then((result) => {
       console.log("更新订单【" + this.orderNo + "】状态:" + statusCode);
    }).catch( (error)=>{
       this.$message.error("更新订单失败!");
    });
},

com.renda.order.controller.OrderController

代码语言:javascript
复制
package com.renda.order.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.renda.entity.UserCourseOrder;
import com.renda.order.OrderService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author Renda Zhang
 * @since 2020-10-16 1:35
 */
@RestController
@RequestMapping("order")
public class OrderController {

    // 远程消费
    @Reference
    private OrderService orderService;

    ...

    @GetMapping("updateOrder")
    public Integer updateOrder(String orderNo, Integer status) {
        System.out.println("订单编号 = " + orderNo);
        System.out.println("状态编码 = " + status);
        Integer integer = orderService.updateOrder(orderNo, status);
        System.out.println("订单更新 = " + integer);
        return integer;
    }

    ...
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-10-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Renda 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建二维码
  • 准备工作
    • 名词介绍
      • 获取认证的流程
        • 1) 注册公众号 - 类型:服务号
        • 2) 认证公众号
        • 3) 提交材料申请微信支付
        • 4) 开户成功,登录商户平台进行验证
        • 5) 在线签署协议
        • 6) 查看自己的公众号的参数
    • 支付流程
    • 工具介绍
      • 微信支付 SDK
        • `JFinal` 框架
        • 构建二维码
        • 检查支付状态
        • 保存订单并更新状态
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档