开发工具:idea,hbuildx,微信开发工具
微信小程序官方图片
实现支付操作思路及代码
一、登录
1.uni.login()方法获取用户凭证code
2.uni.getUserProfile()方法返回用的昵称,头像等信息,把用户的code,昵称,头像请求后端接口
3.,后端接口用code,appid,secret等封装成map请求微信获取openid的微信api获取用户的openid
4.查询数据库是否存在该openid,没有的话添加进去,然后根据用户ID生成token,把token和expire返回给小程序,存到storage中,小程序每次请求后端接口都要把token放到请求的header里面
//小程序代码
//login方法获取code,code5分钟有效
uni.login({
provider:'weixin',
success:function(res){
let code = res.code;
that.code = code;
console.log("code=>>>"+code)
}
}),
//获取微信用户信息
uni.getUserProfile({
desc:"获取登录用户的信息",
success(res){
console.log(res)
let username = res.userInfo.nickName;
let photo = res.userInfo.avatarUrl;
console.log("username====>"+username);
console.log("photo====>"+photo);
that.username = username;
that.photo =photo;
//请求后台商户系统,返回用户token,存入storage,以后每次请求商户系统都要带有token
uni.request({
url:that.url.wxLogin,
method:"POST",
data:{
"nickname":that.username,
"photo":that.photo,
"code":that.code,
},
success(res){
let token = res.data.token;
let expire = res.data.expire;
console.log("token====>"+token)
console.log("expire====>"+expire)
uni.setStorageSync("token",token);
uni.setStorageSync("expire",expire);
uni.switchTab({
url:"../index/index",
})
}
})
}
})
//后端代码
@PostMapping("/login")
@ApiOperation("登录")
public R login(@RequestBody WxLoginForm form){
//表单校验
ValidatorUtils.validateEntity(form);
Map<String, Object> map = new HashMap<>();
map.put("appid", wxConfiguration.getAppId());
map.put("secret", wxConfiguration.getAppSecret());
map.put("js_code", form.getCode());
map.put("grant_type", "authorization_code");
String response = HttpUtil.post(wxConfiguration.getLoginUrl(), map);
JSONObject jsonObject = JSONUtil.parseObj(response);
String openid = jsonObject.getStr("openid");
if (openid == null || StringUtils.isBlank(openid)) {
return R.error("微信登录凭证不正确!");
}
LambdaQueryWrapper<UserEntity> ew = new LambdaQueryWrapper<>();
ew.eq(UserEntity::getOpenId, openid);
UserEntity userEntity = userService.getOne(ew);
String token;
if (userEntity == null) {
UserEntity user = new UserEntity();
user.setNickname(form.getNickname());
user.setOpenId(openid);
user.setPhoto(form.getPhoto());
user.setCreateTime(new Date());
user.setType(EnumUtil.WX.getCode());
userService.save(user);
token = jwtUtils.generateToken(user.getUserId());
}else{
token = jwtUtils.generateToken(userEntity.getUserId());
}
Map<String, Object> result = new HashMap<>();
result.put("token", token);
result.put("expire", jwtUtils.getExpire());
return R.ok(result);
}
二、支付
1.小程序带着订单id和用户token请求后端接口,后端先验证用户和订单的有效性,验证通过后封装参数,调用微信统一下单api获得支付订单的id
2.获得支付订单id后封装数据发送给小程序,小程序把数据发送给微信平台验证支付的正确性,如果正确就返回支付的二维码,支付成功之后调用success()函数,在success函数中可以调用后端接口让主动查询微信支付结果api,看该订单是否支付成功,支付订单支付成功的话就修改商品订单的状态为已付款
小程序代码
pay(id){
let that = this;
uni.request({
url:that.url.mircoPayOrder,
method:"POST",
data:{
"orderId":id,
},
header:{
"token":uni.getStorageSync("token"),
},
success(res){
console.log("pay-res=====>"+res.data);
let timeStamp = res.data.timeStamp;
let nonceStr = res.data.nonceStr;
let paySign = res.data.paySign;
let pk = res.data.package;
console.log("package:"+pk);
console.log("nonceStr:"+nonceStr);
console.log("paySign:"+paySign);
console.log("timeStamp:"+timeStamp);
//小程序向微信支付平台发送请求验证支付的正确性,如果正确会返回支付的页面(支付二维码),支付成功后进入success函数
uni.requestPayment({
"timeStamp":timeStamp,
"nonceStr":nonceStr,
"paySign":paySign,
"package":pk,
"signType":"MD5",
success(res){
uni.showToast({
title:"支付成功"
})
//用户支付成功之后,小程序向后端商户系统发送请求,让商户系统主动查询支付订单结果
uni.request({
url:that.url.activeQueryOrder,
method:"POST",
header:{
"token":uni.getStorageSync("token")
},
data:{
"orderId":id
},
//成功之后刷新当前页面
success(res){
//getCurrentPages()方法获取所有页面
let pages = getCurrentPages()
//当前页面是最后一个
let page = pages[pages.length - 1]
page.onShow()
},
fail(res){
console.log("修改订单状态失败=====>"+id)
}
})
},
fail(res){
uni.showToast({
title:"支付失败"
})
}
})
},
})
}
后端代码
@Login
@PostMapping("/microAppPayOrder")
@ApiOperation("小程序支付")
public R microAppPayOrder(@RequestBody PayOrderForm form, @RequestHeader HashMap<String, Object> map) {
ValidatorUtils.validateEntity(form);
String token = map.get("token").toString();
Integer userId = Integer.parseInt(jwtUtils.getClaimByToken(token).getSubject());
LambdaQueryWrapper<UserEntity> uew = new LambdaQueryWrapper<>();
uew.eq(UserEntity::getUserId, userId);
UserEntity user = userService.getOne(uew);
if (user == null) {
return R.error("用户不存在!");
}
Integer orderId = form.getOrderId();
LambdaQueryWrapper<Order> oew = new LambdaQueryWrapper<>();
oew.eq(Order::getId, orderId)
.eq(Order::getUserId,userId);
Order order = orderService.getOne(oew);
if (order == null) {
return R.error("该用户没有此订单!");
}
if (!Objects.equals(order.getStatus(), EnumUtil.PAY_STATUS_NO_PAY.getCode())) {
return R.error("该订单已支付!");
}
//判断优惠券是否过期
//判断活动是否过期
//向微信平台发送创建支付订单的请求
try {
String openId = user.getOpenId();
//微信支付的单位是分,要转换一下
String amount = String.valueOf(order.getAmount().multiply(BigDecimal.valueOf(100)).intValue());
WXPay wxPay = new WXPay(wxPayConfig);
Map<String, String> paramMap = new HashMap<>();
String nonceStr = WXPayUtil.generateNonceStr();
paramMap.put("nonce_str", nonceStr); //随机字符串
paramMap.put("body", "商品备注信息");
paramMap.put("out_trade_no", order.getCode()); //商品订单流水号,必须为一
paramMap.put("total_fee", amount); //订单金额
paramMap.put("spbill_create_ip", "127.0.0.1");
paramMap.put("notify_url", "127.0.0.1/notify"); //异步通知url 必须为外网地址
paramMap.put("trade_type", "JSAPI"); //交易类型
paramMap.put("openid", openId);
Map<String, String> result = wxPay.unifiedOrder(paramMap);
log.info("result:{}",result);
//支付订单Id
String prepayId = result.get("prepay_id");
if (StringUtils.isNotBlank(prepayId)) {
order.setPrepayId(prepayId);
orderService.updateById(order);
}else {
log.error("微信支付出现异常,订单号:{}",orderId);
return R.error("微信支付出现异常,订单号:{}" + orderId);
}
//发送数据给小程序
paramMap.clear();
paramMap.put("appId", wxConfiguration.getAppId());
String timeStamp = String.valueOf(new Date().getTime());
paramMap.put("timeStamp", timeStamp);
paramMap.put("nonceStr", nonceStr);
paramMap.put("package", "prepay_id=" + prepayId);
paramMap.put("signType", "MD5");
//根据组装的map和商户密钥生成签名
String paySign = WXPayUtil.generateSignature(paramMap, wxConfiguration.getMchKey());
return R.ok().put("package", "prepay_id=" + prepayId)
.put("timeStamp", timeStamp)
.put("nonceStr", nonceStr)
.put("paySign", paySign);
} catch (Exception e) {
e.printStackTrace();
log.error("微信支付出现异常,订单号:{}",orderId);
return R.error("微信支付出现异常,订单号:{}" + orderId);
}
}
@PostMapping("/activeQueryOrder")
@ApiOperation("向微信平台发起请求主动查询支付订单状态")
public R activeQueryOrder(@RequestBody ActiveQueryOrderForm form,
@RequestHeader HashMap<String,Object> header) {
ValidatorUtils.validateEntity(form);
//0.先判断该用户下面有没有此订单
String token = header.get("token").toString();
Integer userId = Integer.parseInt(jwtUtils.getClaimByToken(token).getSubject());
String orderId = form.getOrderId();
LambdaQueryWrapper<Order> ew = new LambdaQueryWrapper<>();
ew.eq(Order::getUserId, userId)
.eq(Order::getId, orderId);
Order order = orderService.getOne(ew);
if (order == null) {
return R.error("该用户没有此订单!");
}
//1.向微信平台发起请求查询订单是否支付成功
Map<String, String> map = new HashMap<>();
map.put("appid", wxConfiguration.getAppId());
map.put("mch_id", wxConfiguration.getMchId());
map.put("out_trade_no", order.getCode());
map.put("nonce_str", WXPayUtil.generateNonceStr());
try {
String sign = WXPayUtil.generateSignature(map, wxConfiguration.getMchKey());
map.put("sign", sign);
WXPay wxPay = new WXPay(wxPayConfig);
Map<String, String> result = wxPay.orderQuery(map);
String returnCode = result.get("return_code");
String resultCode = result.get("result_code");
String tradeState = result.get("trade_state");
if ("SUCCESS".equals(resultCode) && "SUCCESS".equals(returnCode)) {
if ("SUCCESS".equals(tradeState)) {
order.setStatus(EnumUtil.PAY_STATUS_PAIED.getCode());
orderService.updateById(order);
return R.ok("微信支付成功,订单状态已修改为已支付!");
}
}
log.error("微信支付失败!订单号:{}",orderId);
return R.error("微信支付失败!");
} catch (Exception e) {
e.printStackTrace();
log.error("微信支付失败!订单号:{}",orderId);
return R.error("微信支付失败!");
}
}
@ApiOperation("微信异步通知")
@PostMapping("/receiveWxMsg1")
public String receiveWxMsg1(@RequestBody String messsge) throws Exception {
log.info("message:====>{}", messsge);
Map<String, String> map = WXPayUtil.xmlToMap(messsge);
String resultCode = map.get("result_code");
String returnCode = map.get("return_code");
String outTradeNo = map.get("out_trade_no");
if ("SUCCESS".equals(resultCode) && "SUCCESS".equals(returnCode)) {
LambdaQueryWrapper<Order> ew = new LambdaQueryWrapper<>();
ew.eq(Order::getCode, outTradeNo);
Order order = new Order();
order.setStatus(EnumUtil.PAY_STATUS_PAIED.getCode());
orderService.update(order, ew);
return "<xml>\n" +
" <return_code><![CDATA[SUCCESS]]></return_code>\n" +
" <return_msg><![CDATA[OK]]></return_msg>\n" +
"</xml>";
}
return null;
}