Spring Boot整合微信支付分

微信支付分是基于用户支付行为等数据的评分,用于免押租借、免押速住、先享后付和智慧零售等场景。商户可通过设置分数门槛筛选用户,提供免密代扣和催收服务。文章详细介绍了微信支付分的开通方式、应用场景,并展示了前后端如何对接微信支付分,包括用户授权、签约验证、订单创建、支付和退款等流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

微信支付分

一.微信支付分介绍
1.1 什么是微信支付分

微信支付分是对个人的身份特质、支付行为、使用历史等情况的综合计算分值,旨在为用户提供更简单便捷的生活方式。
(1)用户可在具体应用场景中,开通微信支付分,此为最常见的开通方法。开通后,用户可以在【微信 > 我 > 服务 > 钱包 > 支付分】中查看分数和使用记录。

在这里插入图片描述

(2)用户可在【微信 > 我 > 服务 > 钱包 > 支付分】直接点击,刷脸开通,此方法开通支付分后,用户仅能查看自己的分数,如需使用应用场景中的服务,仍需在应用场景中开启服务

在这里插入图片描述

说明:用户只需在某一个应用场景中开通一次(开通分数+开通免密代扣),即可在其他应用场景使用支付分功能,无需再次开通分数或开通免密代扣。

1.2 微信支付分应用场景
  • 免押租借:适用于物品租借场景,例如共享充电宝、共享雨伞、线上租赁平台等场景,用户支付分达到商户设置的分数门槛,即有机会获得免交押金权益。
  • 免押速住:适用于酒店行业,用户支付分达到商户设置的分数门槛,即有机会获得免住宿押金,免预付房费等权益。
  • 先享后付:适用于需预付费等场景,例如:电商、网约车、寄快递、电动车充电、共享按摩椅等,用户支付分达到商户设置的分数门槛,即有机会获得先享受服务,后付款的权益。
  • 智慧零售:适用于无人零售机柜,用户支付分达到商户设置的分数门槛,即有机会开柜购物。
1.3 商户接入微信支付分意义
  • 设置分数门槛,筛选合适用户的能力,分数达到或超过该分数门槛的用户,才可以享受对应的服务(例如免押金,免预充值等)。
  • 免密代扣能力,服务结束后,进行免密扣款。
  • 催收能力。

在这里插入图片描述

二.微信支付分实战
2.1 微信支付分对接流程图

前后端实现微信支付分对接流程图:
在这里插入图片描述

  • 1.微信用户扫描二维码进入购买小程序,此时微信用户没有授权。返回用户登录授权界面。
  • 2.微信用户发启同意授权这个操作。
  • 3.前端获取微信用户授权这个动作。
  • 4.根据用户授权动作去调用微信授权接口。
  • 5.微信返回当前微信用户加密过后的jsCode。
  • 6.前端封装jsCode参数调用后端接口。
  • 7.后端接口通过mchid,appid,jsCode参数调用微信解析用户信息接口。
  • 8.解析成功得到当前微信用户的session_key,openid并存入数据库中。
  • 9.微信用户成功进入到购买小程序中(这里的2到8步骤几乎都是一瞬间就执行的事,现实生活中,微信用户点击用户授权就进入购买小程序中!用户无法感知2到8步骤所执行的流程!)
  • 10.用户使用购买小程序,需要签约微信支付分。
  • 11.前端根据用户信息调用后端接口。
  • 12.后端接口通过用户信息拿到对应的openid调用微信是否签约接口。
  • 13.得到是否签约微信支付分结果。
  • 这里根据签约结果有两种不同的流程走向:
  • 第一种走向 Y:
  • 14.验证已经签约微信支付分,则返回信息给前端。
  • 15.用户即可使用购买小程序进行免密支付!
  • 第二种走向 N:
  • 14.验证当前用户openid没有签约微信支付分,则后端通过openid调用微信签约支付分接口。
  • 15.签约微信支付分接口返回一个sign_token给后端,此时还没有签约成功。
  • 16.后端将sign_token返回给前端。
  • 17.前端通过sign_token调用微信支付分确认签约接口。此时签约成功。
  • 18.微信支付分签约成功后,微信回调后端接口。同时用户即可使用购买小程序进行免密支付!这里两个是异步进行的。
2.2 微信支付分代码实战

单元测试代码:

@SpringBootTest
@Slf4j
public class UserMpApiApplicationTests {

    @Resource
    private WxPayConfigHandler wxPayConfigHandler;

    @Resource
    private AppProperties appProperties;

    @Resource
    private WxMaService wxMaService;

    @Resource
    private UserService userService;

    @Resource
    private RedisService redisService;

    @Bean(name = "myWxPayService")
    public WxPayService wxPayService() {
        return new WxPayServiceImpl(
                WxPayConfig.builder()
                        .appId(appProperties.getWxPayScorConfig().getAppId())
                        .mchId(appProperties.getWxPayScorConfig().getMchId())
                        .apiV3Key(appProperties.getWxPayScorConfig().getApiV3Key())
                        .certSerialNo(appProperties.getWxPayScorConfig().getCertSerialNo())
                        .certPrivateKey(appProperties.getWxPayScorConfig().getCertPrivateKey())
                        .serviceId(appProperties.getWxPayScorConfig().getServiceId())
                        .build()
        );
    }

    @Resource
    private WxPayService myWxPayService;

    // 公司微信支付分流程(文字描述)

    // 用户第一次扫描货柜二维码时,需要登录,这个时候前端通过微信接口获取微信用户的jsCode传给后端,后端拿着jsCode通过mchid等参数调用微信解析接口获取到用户手机号,openid等

    // 获取到用户手机号,openid存入user表中

    // 货柜开门之前,后端需要判断当前用户是否签约微信支付分,如果当前用户没有,则返回用户对应的签约支付分信息给前端,让前端回显给用户签约,这里签约是前端通过参数直接调用微信签约接口,签约成功回调后端接口

    // 公司微信支付分流程(代码实现)

    // 登录得到jsCode这个需要前端调微信接口 我们通过jsCode调微信接口解析得到用户手机号,openid等

    // 微信授权用户登录 获取用户信息
    @Test
    public void wxUserlogin(String jsCode) throws WxErrorException {
        WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.getUserService().getSessionInfo(jsCode);
        log.info("解析得到用户信息为:" + wxMaJscode2SessionResult);
    }


    // 从user表中,取出两个用户的openId
    // 手机号         openId                         姓名     是否签约支付分
    // 187****2275  ow_bf4pMuDRUWEBt9U7BKbBFAxXU   魏*        是
    // 150****1233  ow_bf4pkyYlKbQUJfy8DddJa0IrE   冯**       是
    // ow_bf4pMuDRUWEBt9U7BKbBFAxXU 验证签约结果为:PayScorePermitQueryResult(appId=wx99bdea96b81e039d, mchId=1607014288, serviceId=00004000000000161536318681131017, openId=ow_bf4pMuDRUWEBt9U7BKbBFAxXU, authorizationCode=20221019185927000016, authorizationState=AVAILABLE, cancelAuthorizationTime=null, authorizationSuccessTime=2022-10-19T18:59:37+08:00)
    // ow_bf4pMuDRUWEBt9U7BKbBFAxXU 验证签约结果为:PayScorePermitQueryResult(serviceId=00004000000000161536318681131017, openId=ow_bf4pMuDRUWEBt9U7BKbBFAxXU, authorizationCode=20221019185927000016, authorizationState=UNAVAILABLE, cancelAuthorizationTime=2023-05-18T16:08:31+08:00, authorizationSuccessTime=2022-10-19T18:59:37+08:00)
    // ow_bf4pkyYlKbQUJfy8DddJa0IrE 验证签约结果为:PayScorePermitQueryResult(appId=wx99bdea96b81e039d, mchId=1607014288, serviceId=00004000000000161536318681131017, openId=ow_bf4pkyYlKbQUJfy8DddJa0IrE, authorizationCode=20220826122959006796, authorizationState=AVAILABLE, cancelAuthorizationTime=null, authorizationSuccessTime=2022-08-26T12:30:05+08:00)
    // authorizationState=AVAILABLE 说明签约成功
    // authorizationState=UNAVAILABLE 说明没签约
    // 验证用户是否签约支付分
    @Test
    public void signCheck() {

        PayScorePermitQueryResult papPayContractQueryResult = wxPayConfigHandler.wxPayConfig(0L).getPayScoreService().permitQuery("ow_bf4pMuDRUWEBt9U7BKbBFAxXU");
        log.info("验证签约结果为:" + papPayContractQueryResult);

    }

    // 用户没有签约支付分 则查询支付分参数返回给前端调用微信接口进行签约
    @Test
    public void signInfo() {

        // 获取用户登录购买小程序时的信息
        User user = userService.getByOpenId("ow_bf4pMuDRUWEBt9U7BKbBFAxXU");
        // 唯一
        String authCode = DateUtils.format(new Date(), "yyyyMMddHHmmss") + String.format("%06d", redisService.getLoopId(RedisIDKeyEnum.USER));

        PayScorePermitCreateResult payScorePermitCreateResult = wxPayConfigHandler.wxPayConfig(0L).getPayScoreService().permitCreate(
                PayScorePermitCreateRequest.builder()
                        .authorizationCode(authCode)
                        .notifyUrl(appProperties.getDomain() + "/user/sign/" + user.getId() + "/" + 0 + "/wx_notify/v1")
                        .build()
        );
        log.info("微信签约用户:" + user.getId() + "------" + JSON.toJSONString(payScorePermitCreateResult));
        Map<String, String> rtnMap = new HashMap<>();
        if (payScorePermitCreateResult != null && payScorePermitCreateResult.getCode().equals("SUCCESS")) {
            rtnMap.put("sign_token", payScorePermitCreateResult.getApplyPermissionsToken());
            rtnMap.put("apply_permissions_token", payScorePermitCreateResult.getApplyPermissionsToken());
        }
        // 注意:这里的如果前端不授权确认调用微信接口,则授权支付分失败。只有前端根据token调用微信接口成功后回调我们接口进行逻辑处理
        log.info("前端根据tokne调用微信接口授权支付分:" + rtnMap);
    }

    // 创建微信支付分订单 
    @Test
    public void createOrder() {
        // 订单id
        String orderId = "1234567894";
        // 公司商户id
        String mctId = "21090911402000008";

        // 微信支付分创建订单
        PayScoreOrderCreateResult payScoreOrderCreateResult = wxPayConfigHandler.wxPayConfig(0L).getPayScoreService().orderCreate(
                PayScoreOrderCreateRequest.builder()
                        // 订单号
                        .outOrderNo(orderId)
                        .serviceIntroduction("智慧零售")
                        .location(
                                PayScoreOrderCreateRequest.Location.builder()
                                        .startLocation("魏凯的商户测试")
                                        .endLocation("魏凯的商户测试")
                                        .build()
                        )
                        .timeRange(
                                PayScoreOrderCreateRequest.TimeRange.builder()
                                        .startTime(DateUtils.format(new Date(), "yyyyMMdd"))
                                        .build()
                        )
                        .riskFund(
                                PayScoreOrderCreateRequest.RiskFund.builder()
                                        .name("ESTIMATE_ORDER_COST")
                                        .amount(500)
                                        .build()
                        )
                        .attach(mctId)
                        .notifyUrl(appProperties.getPaymentApi() + "/pay_score/notify/pay/" + mctId + "/" + orderId)
                        // 微信用户在商户对应appid下的唯一标识。
                        .openId("ow_bf4pMuDRUWEBt9U7BKbBFAxXU")
                        .needUserConfirm(false)
                        .build()
        );
        log.info("订单创建成功:" + payScoreOrderCreateResult);
    }

    // 取消订单
    @Test
    public void closeOrder() {

        PayScoreOrderCancelResult payScoreOrderCancelResult = myWxPayService.getPayScoreService().orderCancel("1234567891", "取消支付分订单");
        log.info("取消支付分订单:" + payScoreOrderCancelResult);

    }

    // state CREATED:商户已创建服务订单;DOING:服务订单进行中;DONE:服务订单完成;REVOKED:商户取消服务订单;
    // 查询订单
    @Test
    public void queryOrder() {

        PayScoreOrderQueryResult payScoreOrderQueryResult = myWxPayService.getPayScoreService().orderQuery("1234567892");
        log.info("当前订单状态:" + payScoreOrderQueryResult);
    }

    // 订单完结(付款)
    @Test
    public void payOrder() {
        List<PayScoreOrderCompleteRequest.PostPayment> postPayments = new ArrayList<>();
        postPayments.add(
                PayScoreOrderCompleteRequest.PostPayment.builder()
                        .name("用户购物")
                        // 1分钱
                        .amount(1)
                        .build()
        );

        PayScoreOrderCompleteResult payScoreOrderCompleteResult = myWxPayService.getPayScoreService().orderComplete(
                "1234567894",
                PayScoreOrderCompleteRequest.builder()
                        .postPayments(postPayments)
                        // 1分钱
                        .totalAmount(1)
                        .timeRange(
                                PayScoreOrderCompleteRequest.TimeRange.builder()
                                        .endTime(DateUtils.format(new Date(), "yyyyMMdd"))
                                        .build()
                        )
                        .build()
        );
        log.info("支付分订单完结:" + JSON.toJSONString(payScoreOrderCompleteResult));
    }

    // 订单退款
    @Test
    public void refundOrder() {
        // 这个参数是订单支付成功后,回调所得到的。每个订单号支付成功对应一个微信支付成功单号
        String wxOrderId = "4200001866202305188849577870";
        String refundId = DateUtils.format(new Date(), "yyMMddHHmmss") + "0" + String.format("%05d", redisService.getLoopId(RedisIDKeyEnum.TRANSACTION));
        WxPayOrderRefundResult payScorePermitCreateResult = myWxPayService.orderRefund(
                WxPayOrderRefundRequest.builder()
                        // 原支付交易对应的微信订单号 不是我们的orderId
                        .transactionId(wxOrderId)
                        // 商户系统内部的退款单号
                        .outRefundNo(refundId)
                        .notifyUrl(appProperties.getPaymentApi() + "/pay_score/notify/refund/" + wxOrderId + "/" + refundId)
                        .amount(
                                WxPayOrderRefundRequest.Amount.builder()
                                        // 退款金额
                                        .refund(1)
                                        // 原订单金额
                                        .total(1)
                                        .currency("CNY")
                                        .build()
                        )
                        .build()
        );
        log.info("订单退款:" + payScorePermitCreateResult);
    }

}

启动时,注入类介绍:

在这里插入图片描述
通过前端直接请求微信用户授权接口返回的jsCode调用后端接口解析出当前微信用户的openId:

    @Test
    public void wxUserlogin(String jsCode) throws WxErrorException {
        WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.getUserService().getSessionInfo(jsCode);
        log.info("解析得到微信用户标识信息为:" + wxMaJscode2SessionResult);
    }

在这里插入图片描述

根据用户授权得到的openId验证当前用户是否签约微信支付分:

 @Test
    public void signCheck() {

        PayScorePermitQueryResult papPayContractQueryResult = myWxPayService.getPayScoreService().permitQuery("ow_bf4pMuDRUWEBt9U7BKbBFAxXU");
        log.info("验证签约结果为:" + papPayContractQueryResult);

    }

验证签约结果为:PayScorePermitQueryResult(serviceId=00004000000000161536318681131017, openId=ow_bf4pMuDRUWEBt9U7BKbBFAxXU, authorizationCode=20221019185927000016, authorizationState=AVAILABLE, cancelAuthorizationTime=null, authorizationSuccessTime=2022-10-19T18:59:37+08:00)
authorizationState=AVAILABLE 说明已成功,authorizationState=UNAVAILABLE 说明没签约

查询支付分参数返回给前端调用微信接口进行签约:

 @Test
    public void signInfo() {
        // 获取用户登录购买小程序时的信息 openId
        User user = userService.getByOpenId("ow_bf4pMuDRUWEBt9U7BKbBFAxXU");
        // 用户每次签约支付分的唯一标识 
        String authCode = DateUtils.format(new Date(), "yyyyMMddHHmmss") + String.format("%06d", redisService.getLoopId(RedisIDKeyEnum.USER));

        PayScorePermitCreateResult payScorePermitCreateResult = myWxPayService.getPayScoreService().permitCreate(
                PayScorePermitCreateRequest.builder()
                		// 唯一标识 
                        .authorizationCode(authCode)
                        // 前端通过sign_token调用微信签约接口成功时,回调地址
                        .notifyUrl(appProperties.getDomain() + "/user/sign/" + user.getId() + "/" + 0 + "/wx_notify/v1")
                        .build()
        );
        log.info("微信签约用户:" + user.getId() + "------" + JSON.toJSONString(payScorePermitCreateResult));
        Map<String, String> rtnMap = new HashMap<>();
        if (payScorePermitCreateResult != null && payScorePermitCreateResult.getCode().equals("SUCCESS")) {
            rtnMap.put("sign_token", payScorePermitCreateResult.getApplyPermissionsToken());
            rtnMap.put("apply_permissions_token", payScorePermitCreateResult.getApplyPermissionsToken());
        }
        // 注意:这里的如果前端不授权确认调用微信接口,则授权支付分失败。只有前端根据token调用微信接口成功后回调我们接口进行逻辑处理
        log.info("前端根据tokne调用微信接口授权支付分:" + rtnMap);
    }

创建微信支付分订单:

 // 创建微信支付分订单
    @Test
    public void createOrder() {
        // 订单id 随便填一个
        String orderId = "1234567896";

        // 微信支付分创建订单
        PayScoreOrderCreateResult payScoreOrderCreateResult = myWxPayService.getPayScoreService().orderCreate(
                PayScoreOrderCreateRequest.builder()
                        // 订单号
                        .outOrderNo(orderId)
                        .serviceIntroduction("智慧零售")
                        .location(
                                PayScoreOrderCreateRequest.Location.builder()
                                        .startLocation("魏凯的商户测试")
                                        .endLocation("魏凯的商户测试")
                                        .build()
                        )
                        .timeRange(
                                PayScoreOrderCreateRequest.TimeRange.builder()
                                        .startTime(DateUtils.format(new Date(), "yyyyMMdd"))
                                        .build()
                        )
                        .riskFund(
                                PayScoreOrderCreateRequest.RiskFund.builder()
                                        .name("ESTIMATE_ORDER_COST")
                                        .amount(500)
                                        .build()
                        )
                        .notifyUrl(appProperties.getPaymentApi() + "/pay_score/notify/pay/"  + orderId)
                        // 微信用户在商户对应appid下的唯一标识。
                        .openId("ow_bf4pMuDRUWEBt9U7BKbBFAxXU")
                        .needUserConfirm(false)
                        .build()
        );
        log.info("订单创建成功:" + payScoreOrderCreateResult);
    }

在这里插入图片描述

取消订单:

 @Test
    public void closeOrder() {

        PayScoreOrderCancelResult payScoreOrderCancelResult = myWxPayService.getPayScoreService().orderCancel("1234567896", "取消支付分订单");
        log.info("取消支付分订单:" + payScoreOrderCancelResult);

    }

在这里插入图片描述

查询订单状态:

  // 查询订单
    @Test
    public void queryOrder() {

        PayScoreOrderQueryResult payScoreOrderQueryResult = myWxPayService.getPayScoreService().orderQuery("1234567896");
        log.info("当前订单状态:" + payScoreOrderQueryResult);
    }

在这里插入图片描述

完结订单(付款):

 @Test
    public void payOrder() {
        List<PayScoreOrderCompleteRequest.PostPayment> postPayments = new ArrayList<>();
        postPayments.add(
                PayScoreOrderCompleteRequest.PostPayment.builder()
                        .name("用户购物")
                        // 1分钱
                        .amount(1)
                        .build()
        );

        PayScoreOrderCompleteResult payScoreOrderCompleteResult = myWxPayService.getPayScoreService().orderComplete(
                "1234567896",
                PayScoreOrderCompleteRequest.builder()
                        .postPayments(postPayments)
                        // 1分钱
                        .totalAmount(1)
                        .timeRange(
                                PayScoreOrderCompleteRequest.TimeRange.builder()
                                        .endTime(DateUtils.format(new Date(), "yyyyMMdd"))
                                        .build()
                        )
                        .build()
        );
        log.info("支付分订单完结:" + JSON.toJSONString(payScoreOrderCompleteResult));
    }

在这里插入图片描述
这里支付成功后,会回调接口,获取接口中的transactionId,退款需要用到这个id 4200001885202305196566109027

订单退款:

 @Test
    public void refundOrder() {
        // 这个参数是订单支付成功后,回调所得到的。每个订单号支付成功对应一个微信支付成功单号
        String wxOrderId = "4200001885202305196566109027";
        String refundId = DateUtils.format(new Date(), "yyMMddHHmmss") + "0" + String.format("%05d", redisService.getLoopId(RedisIDKeyEnum.TRANSACTION));
        WxPayOrderRefundResult payScorePermitCreateResult = myWxPayService.orderRefund(
                WxPayOrderRefundRequest.builder()
                        // 原支付交易对应的微信订单号 不是我们的orderId
                        .transactionId(wxOrderId)
                        // 商户系统内部的退款单号
                        .outRefundNo(refundId)
                        .notifyUrl(appProperties.getPaymentApi() + "/pay_score/notify/refund/" + wxOrderId + "/" + refundId)
                        .amount(
                                WxPayOrderRefundRequest.Amount.builder()
                                        // 退款金额
                                        .refund(1)
                                        // 原订单金额
                                        .total(1)
                                        .currency("CNY")
                                        .build()
                        )
                        .build()
        );
        log.info("订单退款:" + payScorePermitCreateResult);
    }

在这里插入图片描述

2.3 微信支付分官方文档

网站地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter6_1_14.shtml

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤居自傲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值