准备条件:两个数据库表,一个在用于在点击的时候生成一个订单号表中存储订单信息。第二个用于存储订单号以及各种支付状态,记录日志的log。
小技巧:动态路由如何设定
一.生成订单信息的步骤 orders/_oid.vue 前面加上下划线
this.$router.push({ path: '/orders/'+ res.data.data.orderId })
asyncData({params,error}){ return orderApi.getOrdersInfo(params.oid).then(res=>{ return{ order: res.data.data.item } }) }
还可以传一些参数在params中都可一获得
1.点击购买时调用接口生成一个订单的基本信息
2.根据订单号查找生成的订单基本信息(用于前端显示页面作用)。
微信生成二维码
准备工作:
(1)微信支付id,商户号,商户key
(2)引入微信相关依赖
<dependencies>
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
微信支付二维码接口
1.生成二维码
@Override
public Map createNative(String orderNo) {
try {
//1.根据订单号查询信息
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("order_no",orderNo);
Order order = orderService.getOne(wrapper);
//2.使用map设置生成二维码的一些参数
Map m = new HashMap();
m.put("appid","wx74862e0dfcf69954");
m.put("mch_id", "1558950191"); //商户号
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("100")).longValue()+""); //订单的价格
m.put("spbill_create_ip", "127.0.0.1"); //创建ip
m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");
m.put("trade_type", "NATIVE"); //支付类型
//3.发送HttpClient请求传递参数,传递参数必须是xml格式,微信提供的固定地址
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
client.setHttps(true);
//执行发送请求
client.post();
//4.得到发送请求返回的结果
String xmlInfo = client.getContent();//得到返回的信息
Map<String, String> resultMap = WXPayUtil.xmlToMap(xmlInfo);
//返回的信息并不完成,页面显示的很多,需要自己在组转一些其他值
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")); //二维码的地址
return resultMap;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
2.查询支付状态
@Override
public Map<String, String> queryPayStatus(String orderNo) {
//1.封装参数
Map m = new HashMap();
m.put("appid","wx74862e0dfcf69954");
m.put("mch_id", "1558950191"); //商户号
m.put("nonce_str", WXPayUtil.generateNonceStr()); //生成随机的字符串,以免重复
m.put("out_trade_no", orderNo); //订单号
//2.发送请求
HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
try {
client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
client.setHttps(true);
client.post();
//3.得到请求返回的内容
String xml = client.getContent();
Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
return resultMap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
注意:都是统一调用微信的接口,设置请求参数获取返回值,其中使用到HttpClient工具类是自己封装好的,需要把map转换为xml格式在进行请求微信的地址。
3.查看支付记录和更新数据库
/**
* 添加支付记录和更新订单状态
* @param map
*/
@Override
public void updateOrdersStatus(Map<String, String> map) {
String orderNo = map.get("out_trade_no"); //返回的订单号
//查询出订单信息
QueryWrapper<Order> wrapper = new QueryWrapper<>();
wrapper.eq("order_no",orderNo);
Order order = orderService.getOne(wrapper);
//更新订单表中的订单状态
if (order.getStatus().intValue() == 1){
return;
}
//不是1进行状态的修改
order.setStatus(1); //更新为1 1为支付成功
orderService.updateById(order);
//向着支付表中添加支付信息
PayLog payLog = new PayLog();
payLog.setOrderNo(order.getOrderNo());//支付订单号
payLog.setPayTime(new Date());
payLog.setPayType(1);//支付类型
payLog.setTotalFee(order.getTotalFee());//总金额(分)
payLog.setTradeState(map.get("trade_state"));//支付状态
payLog.setTransactionId(map.get("transaction_id")); //订单流水号
payLog.setAttr(JSONObject.toJSONString(map));
baseMapper.insert(payLog);
}
前端注意事项:
1.需要VUE组件显示二维码
<qriously :value="payObj.code_url" :size="338"/>
2.需要进行路由跳转模糊跳转(_pid要以下划线开头)
this.$router.push({path:'/pay/'+this.order.orderNo})
3.异步处理(pid为上次路由跳转所带的参数)
asyncData({params,error}){
return orderApi.createNative(params.pid).then(res=>{
return{
payObj: res.data.data
}
})
},
4.需要计时器来进行多次查询支付状态
//页面选然后执行
mounted() {
this.timer = setInterval(()=>{
this.queryOrderStatus(this.payObj.out_trade_no)
},3000)
},
methods:{
queryOrderStatus(orderNo){
orderApi.queryStatus(orderNo).then(res=>{
if (res.data.success) {
//清除定时器
clearInterval(this.timer)
this.$message({
type: 'success',
message: '支付成功!'
})
//跳转到课程详情页面观看视频
this.$router.push({path: '/course/' + this.payObj.course_id})
}
})
}
}
5.若一直在支付中可以在后端设置返回状态配合前端的拦截器进行处理
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
})
}
} else {
return response;
}
}
},