创建二维码
安装 qrcodejs2
(注意:安装的是 qrcodejs2
,不要安装 qrcode
,否则会报错)
npm install qrcodejs2 --save
页面中引入
<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
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";
}
支付流程
用户 -> 打开页面 -> 点击购买 -> 传递商品 id 和价格 -> createCodeController -> 获得价格并搭配商户信息发送给微信进行下单 -> 微信支付系统
微信支付系统 -> 返回支付链接 -> createCodeController -> 返回支付链接 -> 创建支付二维码 -> 用户
用户扫描支付 -> 检查支付状态 —> 传递订单号 —> checkOrderStatusController -> 获得订单号并搭配商户信息发送给微信进行查询订单状态 -> 微信支付系统
微信支付系统 -> 返回支付状态 -> checkOrderStatusController -> 返回支付状态 -> 更新页面信息
工具介绍
微信支付 SDK
微信支付官网下载 SDK:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=11_1
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
主要使用 SDK 中的三个功能:
1、获取随机字符串(生成订单编号)。
WXPayUtil.generateNonceStr();
2、将 map 转换成 xml 字符串(自动添加签名)。
WXPayUtil.generateSignedXml(map,partnerKey);
3、将 xml 字符串转换整 map。
WXPayUtil.xmlToMap(result);
JFinal
框架
JFinal
是基于 Java 语言的极速 web 开发框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展。
JFinal
取代 HttpClient
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal</artifactId>
<version>3.5</version>
</dependency>
构建二维码
src\components\Course.vue
<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
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
<!-- 微信支付二维码-->
<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
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 > 30000) {
return resultMap;
}
// 每隔 3 秒,询问一次微信支付平台
Thread.sleep(3000);
}
}
}
保存订单并更新状态
src\components\Course.vue
// 检查支付状态
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(20);
}
/*
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 = 3;
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
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;
}
...
}
想了解更多,欢迎关注我的微信公众号:Renda_Zhang