1.萤石支付简介及流程

萤石支付,是对第三方支付平台的二次封装。考虑到的目的可能有:1.合资公司的金钱交易需要走总部财务 2.二次封装对接更加容易,与第三方支付sdk的交互都由萤石平台封装完成了。

1.1 支付流程

  1. 通过调用萤石创建订单接口,创建萤石订单,并拿到订单id。
  2. 用上一步获取的订单id调用萤石的拉起支付的接口,获取微信小程序拉起支付界面所需要的参数。
  3. 前端获取上一步参数拉起微信支付界面,输入支付密码并完成支付。这一步支付完成后,小程序api与微信支付做交互。
  4. 提供一个支付结果回调的通知接口给萤石相关人员,该接口地址需要外网可以访问,前端支付完成后,萤石会回调该接口通知此次支付是否成功支付。

*支付流程归纳总结:创建萤石订单——>拉起支付——>前端完成支付——>支付回调——>更新系统订单信息

1.2 前置准备工作

  • 联系相关产品,创建对应的小程序号、商户号。(这一步需产品完成与开发无关)
  • 产品需提供给开发小程序对应的appid和secret秘钥。
  • 若是对接萤石支付,需要萤石支付相关人员提供app(应用唯一标识)、ssid(租户id)、token(签名会用到)。
  • 获取萤石支付文档(可能只能拿到相关接口的api截图),主要需要的api接口有:创建订单接口、调起支付接口、查询订单接口(自测可能会用到)。
  • 提供给萤石相关人员支付成功回调的接口地址(注意:该回调地址必须外网可以访问到)。

1.3 签名

调用萤石支付或者微信支付的接口都会用到签名,不同的平台会有自己的签名规约。

  • 萤石的签名规则如下图所示:

1.4 微信授权登录

微信授权使用的是OAuth2.0授权的方式。通过微信授权,可以获取微信用户在本小程序下对应的openid(在支付的时候会用到),也可以结合自己的登录接口使我们系统与微信账号做一个绑定,后续就不需要重复授权,直接登录就行。

1.4.1 微信授权登录流程

  1. 首先通过前端小程序的wx.login方法获取jscode(这一步需要前端同事操作)
  2. 调用后台提供的授权登录接口,需要传参手机号和上一步获取的code编码。
  3. 调用微信提供的获取openid的接口,api接口地址为:https://api.weixin.qq.com/sns/jscode2session?,请求方式为get
  4. openid以及手机号与本系统的用户账号绑定,具体业务具体分析。

2.支付具体代码实现

2.1 签名方法

@Value("${wechat.pay.token:5dfe2115674e7115}")public void setWechatPayToken(String str){HmacSHA256Util.wechatPayToken = str;}/**** 利用Apache的工具类实现SHA-256加密* @param parameterMap 加密参数* @return*/public static String encryptSHA256Str(Map<String, Object> parameterMap) {if(parameterMap.isEmpty()){return null;}String originalText = getAlphabeticalSort(parameterMap);MessageDigest messageDigest;String encdeStr = "";try {messageDigest = MessageDigest.getInstance("SHA-256");byte[] hash = messageDigest.digest(originalText.getBytes(StandardCharsets.UTF_8));encdeStr = Hex.encodeHexString(hash);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return encdeStr;}/*** @description 根据map首字母进行排序* @date 2022/12/27 15:47* @user mengwei6* @param parameterMap 请求参数* @return*/private static String getAlphabeticalSort(Map<String, Object> parameterMap){// 排序Map<String, Object> sortedMap = parameterMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue,(oldVal, newVal) -> oldVal,LinkedHashMap::new));// 封装StringBuilder sb = new StringBuilder();sortedMap.entrySet().forEach(obj->{ sb.append(obj.getKey()).append(obj.getValue());});return sb+wechatPayToken;}

2.2 创建萤石支付订单

2.2.1 接口api文档

2.2.2 代码实现

/*** 创建萤石萤石订单,并返回订单号* @param timestamp 时间戳* @param mobile 下单人的手机号* @return 预支付订单id*/private String getPreOrderId(Long timestamp,String mobile){log.warn("开始创建萤石萤石订单...");// 封装参数Map<String,Object> paramMap = new HashMap<>();paramMap.put("app",app);paramMap.put("user_name","ezmall");paramMap.put("mobile",mobile);paramMap.put("ssid",ssid);// 这个商品是萤石创建租户的时候默认上架的一个商品,非本系统交易的商品,此商品可以信息可以问萤石相关人员获取paramMap.put("products","[{\"bn\":\"包月套餐1\",\"num\":1,\"price\":\"0.01\"}]");paramMap.put("timestamp",timestamp);// 签名(上面签名方法生成)String sign = HmacSHA256Util.encryptSHA256Str(paramMap);paramMap.put("sign",sign);String response = HttpUtil.post(orderCreateUrl, paramMap);log.warn("获取预支付订单号:{}",response);OpenResultBO<String> result = JSON.parseObject(response, new TypeReference<OpenResultBO<String>>(){});if (PortalConstant.SUCCESS_RETURN.equals(result.getCode()) && StringUtils.isNotEmpty(result.getData())){Map map = JSON.parseObject(result.getData(), Map.class);log.warn("创建萤石订单id为{}",map.get("order_id").toString());return map.get("order_id").toString();}else {log.error("状态码:{},错误信息:{}",result.getCode(),result.getMsg());throw new BaseRuntimeException(PortalResultCode.CREATE_YS_ORDER_FAIL);}}

2.3 拉起支付

2.3.1 接口api文档

2.3.2 代码实现

/*** 调用萤石接口拉起支付* @param preOrderId 萤石订单id* @param amount 金额* @param openId 微信openid* @return*/private String getPay(String preOrderId,String amount,String openId){log.warn("开始拉起萤石支付接口...");// 封装参数Map<String,Object> paramMap = new HashMap<>();paramMap.put("ssid",ssid);paramMap.put("app",app);YsOrderParam ysOrderParam = YsOrderParam.builder().order_no(preOrderId).amount(amount).total_amount(amount).build();List<YsOrderParam> ysOrderList = Collections.singletonList(ysOrderParam);String orderParam = JSONObject.toJSONString(ysOrderList);paramMap.put("order",orderParam);paramMap.put("pm_code","miniapppay");ExtParam extParam = ExtParam.builder().open_id(openId).build();paramMap.put("ext",JSONObject.toJSON(extParam));// 签名String sign = HmacSHA256Util.encryptSHA256Str(paramMap);paramMap.put("sign",sign);String response = HttpUtil.post(getPayUrl, paramMap);log.warn("拉起萤石支付接口获取参数:{}",response);OpenResultBO<String> result = JSON.parseObject(response, new TypeReference<OpenResultBO<String>>(){});if (PortalConstant.SUCCESS_RETURN.equals(result.getCode()) && ObjectUtil.isNotEmpty(result.getData())){log.warn("拉起萤石支付接口调用成功,获取参数为{}",result.getData());return result.getData();}else {log.error("状态码:{},错误信息:{}",result.getCode(),result.getMsg());throw new BaseRuntimeException(PortalResultCode.CALL_YS_PAY);}}

2.4 查询订单状态

2.4.1 接口api文档

2.4.2 代码实现

/*** 查询订单状态是否已支付* @param order 萤石支付订单号* @return*/private boolean checkIsPay(String order){// 封装参数Map<String,Object> paramMap = new HashMap<>();paramMap.put("app",app);paramMap.put("ssid",ssid);paramMap.put("order",order);// 签名String sign = HmacSHA256Util.encryptSHA256Str(paramMap);paramMap.put("sign",sign);String response = HttpUtil.get(queryOrderStatus, paramMap);OpenResultBO<String> result = JSON.parseObject(response, new TypeReference<OpenResultBO<String>>(){});if (PortalConstant.SUCCESS_RETURN.equals(result.getCode()) && StringUtils.isNotEmpty(result.getData())){List<Map> mapList = JSON.parseArray(result.getData(), Map.class);if (CollectionUtils.isEmpty(mapList)){throw new BaseRuntimeException(PortalResultCode.ORDER_NOT_FOUND);}Map map = mapList.get(PortalConstant.ZERO);return Integer.valueOf(String.valueOf(map.get("pay_status"))).equals(PortalConstant.ORDER_PAY_SUCCESS);}else {log.error("状态码:{},错误信息:{}",result.getCode(),result.getMsg());throw new BaseRuntimeException(PortalResultCode.QUERY_ORDER_FAIL);}}

2.5 支付回调接口

2.5.1 接口api文档

2.5.2 代码实现

 @ApiOperation(value = "订单通知-1.3", notes = "支付回调接口")@PostMapping("/orderNotify")public Map<String,Object> orderNotify(@Validated OrderNotifyParam param) {log.warn("================开始获取支付回调==================");Map<String,Object> resultMap = new HashMap<>();if (param == null){log.warn("未获取到回调参数");resultMap.put("code",-1);resultMap.put("data",Collections.emptyList());resultMap.put("message","未获取到回调参数");return resultMap;}log.warn("支付回调接收到的参数:{}",param.toString());Map<String, Object> map = JSON.parseObject(JSON.toJSONString(param), new TypeReference<Map<String, Object>>() {});if (!Objects.isNull(map)){log.warn("================开始校验支付回调签名==================");map.remove("sign");String sign = HmacSHA256Util.encryptSHA256Str(map);if (StringUtils.isNotEmpty(sign) && sign.equals(param.getSign())){if (param.getPay_status() != null && param.getOrder_id() != null){if (param.getPay_status().equals(1)){// 回调更新订单状态,次数更新wechatUserOrderService.paySuccess(param.getOrder_id());log.warn("================获取支付回调结束==================");// 返回调用方resultMap.put("code",200);resultMap.put("data",Collections.emptyList());return resultMap;}}}else {resultMap.put("code",PortalResultCode.SIGN_CHECK_ERROR.getCode());resultMap.put("data",Collections.emptyList());resultMap.put("message",PortalResultCode.SIGN_CHECK_ERROR.getMessage());log.warn(PortalResultCode.SIGN_CHECK_ERROR.getMessage());return resultMap;}}resultMap.put("code",-1);resultMap.put("data",Collections.emptyList());resultMap.put("message","回调参数异常");log.warn("回调参数异常");return resultMap;}

3.前端相关

3.1 微信授权登录

  1. 授权调用wx.login方法获取jscode
  2. 请求后端的微信授权登录接口

3.2 微信拉起支付界面

  1. 调用后台购买支付接口获取拉起支付的参数
  2. 根据拉起支付参数调起微信支付界面
  3. 支付完成之后发送请求给微信支付后端

3.3 支付完成验证是否支付成功

  1. 支付界面输完密码支付成功后,轮询调用后端订单状态的接口。
  2. 正常情况下都可实时获取支付成功,前端应给个支付查询订单状态的loading,并做友好处理。

萤石微信支付对接(小程序版)相关推荐

  1. Python3 微信支付(小程序支付)V3接口

    起因: 因公司项目需要网上充值功能,从而对接微信支付,目前也只对接了微信支付的小程序支付功能,在网上找到的都是对接微信支付V2版本接口,与我所对接的接口版本不一致,无法使用,特此记录下微信支付完成功能 ...

  2. 微信支付(小程序微信支付)

    微信开放平台(分享) 微信支付 - 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式 微信公众平台(公众号,订阅号) 先区分以上三个微信官网概念:分别实现什么功能 小程序支付官方文档:微信 ...

  3. Spring Boot中的微信支付(小程序)

    前言 微信支付是企业级项目中经常使用到的功能,作为后端开发人员,完整地掌握该技术是十分有必要的. 一.申请流程和步骤 图1-1 注册微信支付账号 获取微信小程序APPID 获取微信商家的商户ID 获取 ...

  4. 微信支付,小程序支付V3

    简介: 微信支付的文档就不吐槽了,记录下微信支付,小程序支付的实现 开发前准备 账号申请,公钥私钥啥的去官网开发指引-小程序支付 | 微信支付商户平台文档中心 (qq.com) 核心代码 下单及拉起支 ...

  5. 10亿级存储挑战!看一看、微信广告、微信支付、小程序都在用的存储系统究竟是怎么扛住的?!

    背景:两个十亿级的挑战 PaxosStore 是微信内广泛应用的强一致性的分布式存储系统,它广泛支撑了微信的在线应用,峰值过亿TPS,运行在数千台服务器上,在线服务场景下性能强悍.但在软件开发中没有银 ...

  6. 10亿级存储挑战!看一看、微信广告、微信支付、小程序都在用的存储系统究竟是怎么扛住的?!...

    导读:10亿级,是微信用户的数量级.这个庞大数字的背后,是"看一看"."微信广告"."微信支付"."小程序"等业务对数据 ...

  7. 微信支付(小程序)-java配置

    一:商户号配置与小程序设置 微信支付(小程序)-商户号配置与小程序配置 二:java引入微信jar包 <!-- 微信支付 --><dependency><groupId& ...

  8. 微信支付V3 小程序支付API Java版

    本文目的:快速接通微信支付V3 无需关注细节,实现支付功能,修改配置即可调用 文章目录 接入准备 微信支付流程整理(小程序版) 一.导入微信支付扩展包 二.微信支付工具类 1.签名工具类 2.微信支付 ...

  9. 微信支付(小程序)-java

    微信支付开发者文档微信支付是腾讯公司的支付业务品牌,微信支付提供公众号支付.APP支付.扫码支付.刷卡支付等支付方式.微信支付结合微信公众账号,全面打通O2O生活消费领域,提供专业的互联网+行业解决方 ...

最新文章

  1. ICLR2020 | CS-GNN:用平滑度刻画图信息的使用
  2. 为什么 OLAP 需要列式存储
  3. XP系统,无法创建新的网络连接
  4. 331. Verify Preorder Serialization of a Binary Tree
  5. 【Git】解决remote: ******: Incorrect username or password (access token)方法
  6. 网站关停就没事了?5100万账户文件被盗
  7. 检测Java对象所占内存大小 (转载)
  8. 苏宁双11战报:0点~1点 线上订单同比增72%
  9. nextpolish安装_希望组自主三代组装软件NextDenovo最新版本全球学术开源!
  10. textview 加粗_Android 改变 TextView 内局部样式
  11. 【最小割】HDU 4971 A simple brute force problem.
  12. vc++HOOK API黑客外挂编程必知必会
  13. Struts2 中继承ActionSupport类
  14. 管理系统中计算机er图怎么画,er图怎么画?数据库E-R图画法教程详解
  15. c语言使用三种方法计算圆周率,求用三种方法计算圆周率(C语言)
  16. 《麦肯锡方法》第13章 与客户合作-思维导图
  17. 手写数字识别系统(python+K-近邻完整代码)
  18. 从零学前端第一讲:前端开发是什么?给初学者有什么建议?
  19. 一文搞懂 USB 设备端驱动框架
  20. [渝粤教育] 西南科技大学 投资项目评估 在线考试复习资料

热门文章

  1. Mysql创建数据库表,查看表结构,查看表中数据,查看建表语句
  2. JavaScript实现前端rsa公钥加密,后端Java私钥进行解密
  3. 安卓手机主题软件_【软件来了】安卓手机上的 Photoshop
  4. 必知必会--HashMap扩容机制
  5. iOS开发(OC)——QQ点赞效果
  6. 跳一跳辅助实现思路详解
  7. UE4 控件蓝图与蓝图的交互
  8. 计算机领域中有什么高大上的术语其实描述的是很简单的事物?
  9. 20210317_23期_集成学习(上)_Task02_sklearn构建完整机器学习模型
  10. unity ui 概述_通过此概述了解Unity 2D和Platformer基础知识