前言:
上篇文章讲了怎么利用微信开放平台实现微信扫描登录功能(网站应用微信扫码登录)
此篇将为大家讲解怎么利用微信开放平台在网站应用PC端实现微信扫码支付功能
一、准备工作
首先还是登录 微信开放平台
然后在应用详情里边会看到有一个“微信支付”的功能,此时我们点击“申请开通”;跟随着引导会让我们登录 微信支付平台 进行appId绑定
但是绑定网站应用appId的时候会提示下图信息
下边描述也没有说支持网站应用绑定,这个时候不要慌,我们根据指引去联系腾讯客服,给客服说明我们想要在微信支付平台绑定网站应用。接着客服会让我们填写一下信息
(Tips:腾讯客服很难联系到人工客服,一旦联系成功尽量一次性把信息提供完整,不然再次联系又要等很久了)
把腾讯客服需要的信息提供之后我们能做的就是漫长的等待了,说的是审核预计1-3天,大概等了一天半,然后登录微信开放平台和微信支付平台就可以看到已经绑定成功了,由于是微信后台操作,我们不需要手动再去绑定,现在就可以进行代码开发工作了
二、代码开发
代码部分跟之前的小程序微信支付代码几乎一样,可以看一下之前的文章(微信小程序支付流程及代码实现java+uniapp)
唯一不同的是支付类型不一样,之前的小程序支付使用的是JSAPI方式,在网站PC端也是可以使用这种方式,但是前端需要去引入对应的微信SDK再开发,为了减少前端工作量,这里我们就更换另外一种方式,使用NATIVE方式,使用这种方式,创建统一支付订单之后,会返回一个code_url字段,把这个字段的字符串信息生成二维码,使用微信扫一扫即可完成支付,非常方便
代码修改部分(参考之前文章的代码)
/**
* 创建统一支付订单
* @param payParameterVO 商品信息
* @return 返回结果
*/
@Override
@Transactional
public HashMap<String, String> insertPayRecord(PayParameterVO payParameterVO) {
String title = payParameterVO.getGoodsTitle();
//金额 * 100 以分为单位
BigDecimal fee = BigDecimal.valueOf(1);
BigDecimal RMB = new BigDecimal(payParameterVO.getPrice());
BigDecimal totalFee = fee.multiply(RMB);
try {
WeChatPay weChatPay = new WeChatPay();
weChatPay.setAppid(payProperties.getAppId());
weChatPay.setMch_id(payProperties.getMchId());
weChatPay.setNonce_str(getRandomStringByLength(32));
weChatPay.setBody(title);
weChatPay.setOut_trade_no(getRandomStringByLength(32));
weChatPay.setTotal_fee(df.format(Double.parseDouble(String.valueOf(totalFee))));
weChatPay.setSpbill_create_ip(IpUtils.getHostIp());
weChatPay.setNotify_url(payProperties.getNotifyUrl());
weChatPay.setTrade_type("NATIVE");//JSAPI
//这里直接使用当前用户的openid
weChatPay.setOpenid(payParameterVO.getWxOpenId());
weChatPay.setSign_type("MD5");
//生成签名
String sign = SignUtils.getSign(weChatPay);
weChatPay.setSign(sign);
log.info("订单号:" + weChatPay.getOut_trade_no());
//向微信发送下单请求
String result = HttpRequest.sendPost(WeChatPayUrlConstants.Uifiedorder, weChatPay);
//将返回结果从xml格式转换为map格式
Map<String, String> wxResultMap = WXPayUtil.xmlToMap(result);
System.out.println(wxResultMap);
if (StringUtils.isNotEmpty(wxResultMap.get("return_code")) && wxResultMap.get("return_code").equals("SUCCESS")){
if (wxResultMap.get("result_code").equals("FAIL")){
log.error("微信统一下单失败![{}]", wxResultMap.get("err_code_des"));
return null;
}
}
OrderReturnInfo returnInfo = MapToObject.convertMapToObject(wxResultMap, OrderReturnInfo.class);
// 二次签名
if ("SUCCESS".equals(returnInfo.getReturn_code()) && returnInfo.getReturn_code().equals(returnInfo.getResult_code())) {
SignInfo signInfo = new SignInfo();
signInfo.setAppId(payProperties.getAppId());
long time = System.currentTimeMillis() / 1000;
signInfo.setTimeStamp(String.valueOf(time));
signInfo.setNonceStr(WXPayUtil.generateNonceStr());
signInfo.setRepay_id("prepay_id=" + returnInfo.getPrepay_id());
signInfo.setSignType("MD5");
//生成签名
String sign1 = SignUtils.getSign(signInfo);
HashMap<String, String> payInfo = new HashMap<>();
payInfo.put("placeOrderJsonMsg", JSON.toJSONString(weChatPay));
payInfo.put("orderNum", weChatPay.getOut_trade_no());
PaySignInfo paySignInfo = new PaySignInfo();
paySignInfo.setAppId(signInfo.getAppId());
paySignInfo.setTimeStamp(signInfo.getTimeStamp());
paySignInfo.setNonceStr(signInfo.getNonceStr());
paySignInfo.setRepay_id(signInfo.getRepay_id());
paySignInfo.setSignType(signInfo.getSignType());
paySignInfo.setPaySign(sign1);
payInfo.put("paySignInfo",JSON.toJSONString(paySignInfo));
payInfo.put("payQrcodeUrl", wxResultMap.get("code_url"));
// 业务逻辑结束 回传给小程序端唤起支付
return payInfo;
}
return null;
} catch (Exception e) {
log.error(e.getMessage());
}
return null;
}
就修改两处,一个是trade_type字段改为NATIVE
另外就是返回的时候把code_url也传给前端
另外在实体类中需要加上code_url字段,不然 MapToObject.convertMapToObject 方法会因为字段不匹配而报错
/**
* 预下单成功之后返回结果对象
* @author kun
* {@code @date} 2024/1/30
*/
@Data
public class OrderReturnInfo {
/** 返回状态码 */
private String return_code;
/** 返回信息 */
private String return_msg;
/** 业务结果 */
private String result_code;
/** 小程序appID */
private String appid;
/** 商户号 */
private String mch_id;
/** 随机字符串 */
private String nonce_str;
/** 签名 */
private String sign;
/** 预支付交易会话标识。用于后续接口调用中使用,该值有效期为2小时 */
private String prepay_id;
/** 交易类型 */
private String trade_type;
/** 支付二维码 */
private String code_url;
}
然后前端随便用个二维码生成工具把这个链接生成为二维码就行了,或者后端生成二维码把图片给前端也是可以的。然后扫码付钱即可
支付成功演示:
总结:
网站应用接入微信支付流程也还是比较简单,主要难点是在权限申请那里,很多小伙伴以为绑定不了appId就无法接入使用了,但很多时候只是官方自己没有完善到位,遇到这种情况可以联系一下人工客服再次确认。有的小伙伴可能会说在网站应用使用公众号的appId也可以做微信支付;但这是有一个前提的,就是登录也同样需要使用公众号授权登录,我们上篇文章讲了使用微信开放平台的登录功能,所以要支付的话也同样需要使用微信开放平台的支付功能。因为在创建统一支付订单的时候,是需要校验用户的OpenId、应用的appId、商户号这几个信息的,如果拿着开放平台的用户授权信息又去使用公众号的微信支付,那必然是会提示信息不匹配的。