vue前端
- 安装 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>
<h2 id="statusText"></h2>
<p id="closeText"></p>
</el-dialog>
<script>
import QRCode from "qrcodejs2"; // 引入qrcodejs
import { setInterval, clearInterval } from 'timers';
export default {
name: "Course",
components: {
QRCode // 声明组件
},
data() {
return {
dialogFormVisible: false, // false默认隐藏,true 显示
time:null, // 计时对象
};
},
methods: {
// 购买
buy(courseid) {
// alert("购买第【" + courseid + "】门课程成功,加油!");
this.dialogFormVisible = true; //显示提示框
// 待dom更新之后再用二维码渲染其内容
this.$nextTick(function() {
this.createCode(); // 直接调用会报错:TypeError: Cannot read property 'appendChild' of null
});
},
// 生成支付二维码
createCode() {
// 去获取支付链接
this.axios
.get("http://localhost:80/order/createCode", {
params: {
courseId: this.course.id,
courseName: this.course.courseName,
price: this.course.discounts
}
})
.then(res => {
console.log(res);
// QRCode (存放二维码的dom元素的id,二维码的属性参数)
let qrcode = new QRCode("qrcode", {
width: 200,
height: 200,
text: res.data.result_url // 将返回的数据嵌入到二维码中
});
this.orderNo = res.data.orderId;
// *****************************************
// 真实的修改数据库 保存订单
// this.saveOrder();
// *****************************************
// 检查支付状态
this.axios
.get("http://localhost:80/order/checkOrderStatus", {
params: {
orderId: res.data.orderId // 传递订单编号 进行查询
}
})
.then(res => {
console.log(res);
if(res.data.trade_state == "SUCCESS"){
document.getElementById("statusText").innerHTML = "<i style='color:#00B38A' class='el-icon-success'></i>支付成功"
// *****************************************
// 支付成功后 写后续的逻辑(如更改订单状态)
// *****************************************
}
// 3s后关闭二维码窗口
let s = 3; // 倒计时的秒数
this.closeQRForm(s); // 关闭二维码窗口
})
.catch(err => {
this.$message.error("生成订单失败!");
});
})
.catch(err => {
this.$message.error("生成支付二维码失败!");
});
},
// 倒计时关闭二维码窗口
closeQRForm(s){
let that = this;
that.time = setInterval(function(){
document.getElementById("closeText").innerHTML = "("+ s-- +")秒后关闭本窗口";
if(s == 0){
clearInterval(that.time); // 停止计时器
that.dialogFormVisible = false; // 二维码窗口隐藏
that.isBuy = true;// 修改购买状态(已购买)
}
},1000)
},
}
}
</script>
Java后端
支付配置类
package commons;
/**
* 微信支付商户配置类
*/
public class Payconfig {
//企业公众号ID
public static String appid = "";
// 财付通平台的商户帐号
public static String partner = "";
// 财付通平台的商户密钥
public static String partnerKey = "";
// 回调URL
public static String notifyurl = "";
}
依赖
<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 开发框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展
- 取代HttpClient
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal</artifactId>
<version>3.5</version>
</dependency>
构建二维码
- createCodeController
package com.lagou.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;
/**
* 微信支付相关控制
*/
@RestController
@RequestMapping("order")
public class WxPayController {
// 创建支付二维码
@GetMapping("createCode")
public Object createCode(String courseId,String courseName,String price) throws Exception {
// 编写商品信息写入到map中
Map<String ,String> map = new HashMap();
map.put("appid", Payconfig.appid); // 公众号id
map.put("mch_id",Payconfig.partner); // 商户号
map.put("nonce_str", WXPayUtil.generateNonceStr()); // 随机字符串
courseName = new String(courseName.getBytes("ISO-8859-1"),"UTF-8");
map.put("body",courseName); // 商品简单描述
map.put("out_trade_no",WXPayUtil.generateNonceStr()); // 随机生成的商户订单号
map.put("total_fee",price); // 订单金额 单位为分,只能为整数
map.put("spbill_create_ip","127.0.0.1"); // 终端ip
map.put("notify_url",Payconfig.notifyurl); // 通知地址
map.put("trade_type","NATIVE"); // 交易类型
System.out.println("商户信息 = " + map);
// 生成数字签名,并发商户信息转换成xml格式
String xml = WXPayUtil.generateSignedXml(map, Payconfig.partnerKey);
System.out.println("商户的xml信息 = " + xml);
// 将xml数据发送给微信支付平台,从而生成订单
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
// -- 发送请求,返回一个xml格式的字符串
String result = HttpKit.post(url, xml);
// 微信支付平台返回xml格式数据,将其转换成map格式并返回给前端
Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
resultMap.put("orderId",map.get("out_trade_no"));
System.out.println("返回的xml,转换成map = " + resultMap);
return resultMap;
}
// 查看支付状态
@GetMapping("checkOrderStatus")
public Object checkOrderStatus(String orderId) throws Exception {
// 编写商户信息
// 编写商品信息写入到map中
Map<String ,String> map = new HashMap();
map.put("appid", Payconfig.appid); // 公众号id
map.put("mch_id",Payconfig.partner); // 商户号
map.put("out_trade_no",orderId); // 商户订单号
map.put("nonce_str", WXPayUtil.generateNonceStr()); // 随机字符串
// 生成数字签名
String xml = WXPayUtil.generateSignedXml(map, Payconfig.partnerKey);
// 发送查询请求给微信支付平台
String url = "https://api.mch.weixin.qq.com/pay/orderquery";
// 查询订单状态的开始时间点
long beginTime = System.currentTimeMillis();
// 不停的去微信支付平台询问是否支付成功
while (true){
// 对微信支付平台返回的查询结果进行处理
String result = HttpKit.post(url, xml);
Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
// 已经支付成功,不再询问
if(resultMap.get("trade_state").equalsIgnoreCase("SUCCESS")){
return resultMap;
}
// 超过30s 未支付 ,停止询问
if (System.currentTimeMillis() - beginTime > 30000){
return resultMap;
}
Thread.sleep(3000); // 每隔3s,询问一次微信支付平台
}
}
}
解决中文乱码
new String(coursename.getBytes("ISO-8859-1"),"UTF-8");