前言:

上篇文章讲了怎么利用微信开放平台实现微信扫描登录功能(网站应用微信扫码登录)

此篇将为大家讲解怎么利用微信开放平台在网站应用PC端实现微信扫码支付功能

一、准备工作

首先还是登录 微信开放平台

然后在应用详情里边会看到有一个“微信支付”的功能,此时我们点击“申请开通”;跟随着引导会让我们登录 微信支付平台 进行appId绑定

但是绑定网站应用appId的时候会提示下图信息

下边描述也没有说支持网站应用绑定,这个时候不要慌,我们根据指引去联系腾讯客服,给客服说明我们想要在微信支付平台绑定网站应用。接着客服会让我们填写一下信息

(Tips:腾讯客服很难联系到人工客服,一旦联系成功尽量一次性把信息提供完整,不然再次联系又要等很久了)

把腾讯客服需要的信息提供之后我们能做的就是漫长的等待了,说的是审核预计1-3天,大概等了一天半,然后登录微信开放平台和微信支付平台就可以看到已经绑定成功了,由于是微信后台操作,我们不需要手动再去绑定,现在就可以进行代码开发工作了

二、代码开发

代码部分跟之前的小程序微信支付代码几乎一样,可以看一下之前的文章(微信小程序支付流程及代码实现java+uniapp)

唯一不同的是支付类型不一样,之前的小程序支付使用的是JSAPI方式,在网站PC端也是可以使用这种方式,但是前端需要去引入对应的微信SDK再开发,为了减少前端工作量,这里我们就更换另外一种方式,使用NATIVE方式,使用这种方式,创建统一支付订单之后,会返回一个code_url字段,把这个字段的字符串信息生成二维码,使用微信扫一扫即可完成支付,非常方便

代码修改部分(参考之前文章的代码)

/**

* 创建统一支付订单

* @param payParameterVO 商品信息

* @return 返回结果

*/

@Override

@Transactional

public HashMap 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 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 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、商户号这几个信息的,如果拿着开放平台的用户授权信息又去使用公众号的微信支付,那必然是会提示信息不匹配的。