手把手教你如何采用服务商模式实现微信支付

文章目录

  • 背景
  • 微信支付的模式
  • 一、前期准备
    • 1.注册服务商
    • 2.服务商入驻
      • 页面入驻
      • 申请证书
      • 重要参数说明
  • 二、子商户支付流程
  • 三、实现方案
    • 1.引入依赖
    • 2.支付配置
    • 3.相关配置类
    • 4.业务实现类
    • 5.测试类
    • 6.相关测试
      • 创建支付订单
      • 相应结果
      • 查询订单
      • 相应结果
      • 微信异步回调
  • 总结


背景

小程序盛行时代,一般的企业中都都会包含多个小程序,而大部分的小程序通常都需要实现支付功能,本文将针对服务商模式进行微信支付进行详细讲解。

微信支付的模式


一般企业选用是服务商或者为渠道商模式,但是成为渠道商需要相关流量支撑才能申请,本文以服务商模式进行讲解。


咨询微信支付客服关于服务商的有些问题:
1.服务商和特约只能有一个,需要注销特约商户后申请成为服务商
2.服务商不能单独收款,只能给特约商户进行收款
3.服务商可以设置分账抽成微信会自动完成分账
4.服务商下特约商户收款会直接将钱打到特约商户下
5.直连或者特约可以成为注册另一个服务商下的特约(根据风险适时调整)

一、前期准备

1.注册服务商

服务商申请需要通过已做过公司认证的公众号,登录公司的微信服务号,在【微信支付】>【服务商申请】,直接跟着官方引导一步步操作即可,具体申请流程如下:
在这里插入图片描述
说明:所以企业需要申请公共号,才能申请注册服务商。

2.服务商入驻

通过服务商来开发的系统来帮助商户微信支付,首先需要完成商户号在服务商号中的入驻过程。服务商注册成功后,进入微信支付平台,登录服务商,进行商户入驻。一般商户入驻有两种,具体如下:

  • 页面入驻
  • 调用API方式入驻

页面入驻

在这里插入图片描述
入驻可以看作是商户生成商户号的同时与服务商形成绑定关系。具体可以参考微信公众号中按流程指引一步步操作就行。
在这里插入图片描述

说明:商户入驻完成后,此商户才能用于微信支付。

申请证书

商户号入驻成功后,需要申请API证书。
在这里插入图片描述
说明:按照官方文档申请证书,设置密钥,设置好密钥后一定要在安全的前提下记住,之后只能重置不能查看。

重要参数说明

  • appid:服务商Appid
  • mchId:服务商的商户id
  • mchKey:证书的序列号
  • subAppId:子商户小程序Appid
  • subOpenId:子商户小程序用户的openId
  • subMchId:子商户的商户id

二、子商户支付流程

以下是子商户APP中调用支付的交互时序图
在这里插入图片描述
流程说明:

  • 用户在商户APP中选择商品,选择微信支付,提交订单,如图中步骤1-3所示。
  • 调用服务商提供的下单接口,服务商后台收到下单请求,会返回签好名的订单数据,用于商户APP里面调起微信支付,如图中步骤3-5所示。
  • 用户确认支付,输入密码,支付完成,如图中步骤6-8所示。
  • 支付完成后,微信返回商户APP,回调APP实现的回调函数,此时需要根据单号调用服务商提供的查询结果,查询后台实际支付结果,再作用户页面展示和发货操作。如图步骤9-13.

三、实现方案

服务商模式的微信支付的具体实现方案,本文采用的是Spring Boot集成weixin-java-pay来实现微信支付。

1.引入依赖

<dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-pay</artifactId><version>4.1.0</version>
</dependency>

2.支付配置

# 微信支付配置
wx:pay:#服务商idmchId: 12#证书keyPath: apiclient_cert.p12#服务商appidappId: wxe12233#支付回调通知地址notifyUrl: https://localhost:8080/pay/resWxPay#服务商key的密钥mchKey: 123444

3.相关配置类

说明:读取微信支付的配置信息

@Component
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties {/***  小程序appid*/private String appId;/*** 微信支付商户号*/private String mchId;/*** 微信支付商户密钥*/private String mchKey;/*** 服务商模式下的子商户公众账号ID*/private String subAppId;/*** 服务商模式下的子商户号*/private String subMchId;/*** apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定*/private String keyPath;/*** 支付回调*/private String notifyUrl;//省略get、set方法}

说明:将微信支付的相关参数设置到wxjava中的cofig中。

/*** 微信支付配置类*/
@Configuration
public class CustWxPayConfig 
{@Autowiredprivate WxPayProperties properties;@Bean@ConditionalOnMissingBeanpublic WxPayService wxService() {WxPayConfig payConfig = new WxPayConfig();payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));//设置微信支付参数WxPayService wxPayService = new WxPayServiceImpl();wxPayService.setConfig(payConfig);return wxPayService;}
}

4.业务实现类

@Service
@Transactional(rollbackFor =Exception.class)
public class CustWxPayServiceImpl implements CustWxPayService
{private Logger logger = LoggerFactory.getLogger(CustWxPayService.class);@Autowiredprivate WxPayService wxService; public void createWxPayOrder(WxPayObject payObject){logger.info("Create wx pay order.");//并发控制WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();request.setTradeType(payObject.getTradeType()); int payMoney = payObject.getPayMoney().multiply(new BigDecimal(100)).intValue();// totalFee单位为(分)request.setTotalFee(payMoney);//第三方订单号request.setOutTradeNo(payObject.getOrderNo());//用户OpenID(支付小程序)request.setSubOpenid(payObject.getSubOpenid());//支付小程序APPIDrequest.setSubAppId(payObject.getSubAppId()); request.setNonceStr(getRandomString(32));request.setBody(payObject.getBody());         request.setFeeType(payObject.getFeeType());         HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();//IP地址request.setSpbillCreateIp(IpUtil.getIpAddr(httpRequest));//配置回调地址request.setNotifyUrl(wxService.getConfig().getNotifyUrl());//收款子商户String subMchId = wxService.getConfig().getSubAppId();request.setSubMchId(subMchId);//DeviceIDrequest.setDeviceInfo(payObject.getDeviceInfo());//支付类型:request.setTradeType(payObject.getTradeType());//创建建订单WxPayMpOrderResult wxPayMpOrderResult =null;try{wxPayMpOrderResult = wxService.createOrder(request);if (wxPayMpOrderResult == null){logger.info("Create Wx Order Success. Result is null.");}else{logger.info("Create Wx Order Success. Result:{}",JSON.toJSONString(wxPayMpOrderResult));}}catch (WxPayException e){logger.error("createWxPayOrder error",e);throw new SysException("create wx order error",e);     }}@Overridepublic void resWxPay(String xmlData){logger.info("Wx Pay Response, param[{}]", xmlData);WxPayOrderNotifyResult result =null;try{result = wxService.parseOrderNotifyResult(xmlData);//支付失败if ("FAIL".equalsIgnoreCase(result.getResultCode()) || "FAIL".equalsIgnoreCase(result.getReturnCode())){//记录支付失败错误日志throw new SysException(result.getErrCodeDes());              }//获取订单号String outTradeNo = result.getOutTradeNo();if (StringUtils.contains(outTradeNo, "_")){outTradeNo = outTradeNo.substring(0, outTradeNo.indexOf("_"));}//执行具体业务逻辑//记录流水//更新订单状态            }catch (WxPayException e){throw new SysException("wx pay error",e);     }}@Overridepublic WxPayOrderQueryResult queryOrder(String outTradeNo){WxPayOrderQueryResult wxPayOrderQueryResult  =null;try{wxPayOrderQueryResult= wxService.queryOrder(null, outTradeNo);}catch (WxPayException e){throw new SysException("query wx order error",e);     }return wxPayOrderQueryResult;}public static String getRandomString(int length) {String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";Random random = new Random();StringBuffer sb = new StringBuffer();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}}

说明:实现微信创建订单、支付回调、查询订单接口。

5.测试类

@RestController
@RequestMapping("/pay/wxpay/")
public class WxPayController
{private Logger logger =LoggerFactory.getLogger(WxPayController.class);@Autowiredprivate CustWxPayService custWxPayService;/*** * @param subAppId 小程序AppId* @param subOpenid 用户在小程序的openid* @param payMoney 支付金额* @param orderNo 第三方订单号* @return*/@PostMapping("/reqWxPay")public Result reqWxPay(@RequestBody WxPayObject wxPayObject){//支付参数验证logger.info("Req Wx Pay,param:{}",JSON.toJSONString(wxPayObject));Result result =new Result();try{//创建订单custWxPayService.createWxPayOrder(wxPayObject);}catch(Exception e){logger.error("Req Wx Pay Error.", e);return Result.error("Req Wx Pay error"+e);}return Result.success(result);}/*** 异步回调* @param xmlData* @return*/@PostMapping("/resWxPay")public String resWxPay(@RequestBody String xmlData){logger.info("Wx Pay Response, Data:[{}]", xmlData);try{custWxPayService.resWxPay(xmlData);}catch(Exception e){logger.error("Wx Pay Response Process Error.", e);return WxPayNotifyResponse.fail("订单支付失败.");}logger.info("Wx Pay Response Process Success.");return WxPayNotifyResponse.success("付款成功");}@GetMapping("/queryOrder")public Result queryOrder(String outTradeNo){WxPayOrderQueryResult wxPayOrderQueryResult = custWxPayService.queryOrder(outTradeNo);logger.info(wxPayOrderQueryResult.toString());return Result.success(wxPayOrderQueryResult);}
}

6.相关测试

创建支付订单

在这里插入图片描述
说明:

  • subAppId:子商户的小程序id
  • subOpenid:小程序用户的openid

相应结果

在这里插入图片描述
说明:returnCode为success,则说明创建微信支付订单成功。

查询订单

订单创建成功后,需要查询订单状态。
在这里插入图片描述

相应结果

在这里插入图片描述

微信异步回调

关于微信支付回调,需要绑定外网域名,在内网需要测试的话,需要进行内网穿透,微信异步回调可能由于网络原因出现延迟,所以在业务上需要提供主动查询和异步回调结合的方式,关于具体实现将在后续的文章中进行讲解。

总结

本文服务商模式实现微信支付进行详细的讲解,实现过程还是比较复杂,订单支付中涉及到重复提交、幂等性验证、同步+异步的轮询处理等问题将在后续的文章中进行讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/164325.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AICFD案例教程】进气歧管分析

AICFD是由天洑软件自主研发的通用智能热流体仿真软件&#xff0c;用于高效解决能源动力、船舶海洋、电子设备和车辆运载等领域复杂的流动和传热问题。软件涵盖了从建模、仿真到结果处理完整仿真分析流程&#xff0c;帮助工业企业建立设计、仿真和优化相结合的一体化流程&#x…

【LearnOpenGL基础入门——2】搭建第一个OpenGL窗口

目录 一.配置GLFW 二.配置GLAD 三.第一个OpenGL窗口 3.1 GLFW设置 3.2 GLAD设置 3.3 视口 3.4 输入 3.5渲染 在我们画出出色的效果之前&#xff0c;首先要做的就是创建一个OpenGL上下文(Context)和一个用于显示的窗口。然而&#xff0c;这些操作在每个系统上都是不一样…

SEO是什么?独立站如何进行SEO优化

创建一个独立网站并不是难事&#xff0c;但要做好独立网站并进行SEO优化以增加自然流量可能是一个不小的挑战。今天&#xff0c;我们将分享一些关于独立网站SEO优化的技巧&#xff0c;并详细探讨如何提升流量。 在本文中&#xff0c;我们将主要关注谷歌SEO&#xff0c;但请不要…

折叠旗舰新战局:华为先行,OPPO接棒

乌云中的曙光&#xff0c;总能带给人希望。 全球智能手机出货量已经连续八个季度下滑&#xff0c;行业里的乌云挥之不散。不过&#xff0c;也能看到高端市场逆势上涨&#xff0c;散发光亮。个中逻辑在于&#xff0c;当前换机周期已经达到了34个月&#xff0c;只有创新产品才能…

10-27 maven概念

maven maven的概念模型: 项目对象模型(POM: Project object Model)&#xff0c;一组标准集合: pom.xml 依赖管理系统(Dependency Management System) 项目生命周期(Project Lifecycle) 项目对象模型&#xff1a; 把项目当成一个对象&#xff0c;描述这个项目&#xff0c;使用p…

【网络管理——操作系统与安全】

文章目录 一、安装WindowsServer操作系统1、新建虚拟机2、进入Windows虚拟机进行相关配置 二、Windows用户账户管理与配置1、创建用户账户2、创建用户组 三、Windows操作系统的本地安全策略设置1、配置用户账户密码策略2、配置用户账户锁定策略3、配置组策略安全选项4、配置审核…

自动还款业务事故案例,与金融场景幂等性思考

一、自动还款业务 事故 案例 事故名称&#xff1a; 自动还款业务事故 事故描述&#xff1a; 事故发生时间&#xff1a;201x-0x-18 0x:15:00 事故响应时间&#xff1a;201x-0x-20 0x:18:00 事故解决时间&#xff1a;201x-0x-20 0x:28:00 事故现象&#xff1a; 自动扣款,出现扣款…

ElasticSearch离线安装

1. 上传和解压软件 将elasticsearch-7.11.2-linux-x86_64.tar.gz和kibana-7.11.2-linux-x86_64.tar.gz 上传到/data/es目录 解压文件 tar -zxvf elasticsearch-7.11.2-linux-x86_64.tar.gz tar -zxvf kibana-7.11.2-linux-x86_64.tar.gz 2. 创建es用户 因为安全问题&#xff…

Java系统操作日志之数据修改变化记录

系统操作日志之数据修改变化记录 前言效果图如何实现总结 相信大家在自己的系统中都有记录日志吧&#xff0c;像登录日志、操作日志等等 但是一般来说&#xff0c;大家都是获取操作了什么东西&#xff0c;包括它的参数&#xff0c;模块等等&#xff0c;但是你有关心过他的数据变…

蓝桥杯每日一题2023.11.6

取位数 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 由题意我们知道len中为现阶段长度&#xff0c;如果其与k相等也就是找到了正确的位数&#xff0c;否则就调用递归来进行搜索&#xff0c;每次搜索一位数。 #include <stdio.h> // 求x用10进制表示时的数位长度 int …

最长非递减子序列,Python实现

from time import time from bisect import bisect from random import choices, seed from itertools import combinationsdef func1(seq):# 暴力穷举&#xff0c;从最长的子序列开始查找&#xff0c;大约耗时5小时for n in range(len(seq)-1, 0, -1): # 依次查找长度为len(se…

四阶龙格库塔与元胞自动机

龙格库塔法参考&#xff1a; 【精选】四阶龙格库塔算法及matlab代码_四阶龙格库塔法matlab_漫道长歌行的博客-CSDN博客 龙格库塔算法 Runge Kutta Method及其Matlab代码_龙格库塔法matlab_Lzh_023016的博客-CSDN博客 元胞自动机参考&#xff1a; 元胞自动机&#xff1a;森林…