java SpringBoot 使用ijpay对接微信支付-商家转账到零钱

使用的maven版本:2.9.11

由于ijpay中提供的实体类没有设置回调参数的属性, 这里是自定义一个实体类:InitiateBatchTransferRequest代码如下:

package com.foo.web.controller.pay.wxpay;import com.ijpay.wxpay.model.v3.TransferDetailInput;
import lombok.Getter;
import lombok.Setter;import java.util.List;public class InitiateBatchTransferRequest {private String appid;           //小程序APPIDprivate String out_batch_no;    //商户单号private String batch_name;      //转账批次名称private String batch_remark;    //转账批次备注private String notify_url;      //回调地址private Integer total_amount;   //转账总金额private Integer total_num;      //转账总笔数private List<TransferDetailInput> transfer_detail_list;//转账明细列表private String transfer_scene_id;//转账场景idpublic InitiateBatchTransferRequest() {}public InitiateBatchTransferRequest(String appid, String out_batch_no, String batch_name, String batch_remark, Integer total_amount, Integer total_num, List<TransferDetailInput> transfer_detail_list, String transfer_scene_id) {this.appid = appid;this.out_batch_no = out_batch_no;this.batch_name = batch_name;this.batch_remark = batch_remark;this.total_amount = total_amount;this.total_num = total_num;this.transfer_detail_list = transfer_detail_list;this.transfer_scene_id = transfer_scene_id;}public String getAppid() {return this.appid;}public String getOut_batch_no() {return this.out_batch_no;}public String getBatch_name() {return this.batch_name;}public String getNotify_url() {return this.notify_url;}public String getBatch_remark() {return this.batch_remark;}public Integer getTotal_amount() {return this.total_amount;}public Integer getTotal_num() {return this.total_num;}public List<TransferDetailInput> getTransfer_detail_list() {return this.transfer_detail_list;}public String getTransfer_scene_id() {return this.transfer_scene_id;}public InitiateBatchTransferRequest setAppid(String appid) {this.appid = appid;return this;}public InitiateBatchTransferRequest setOut_batch_no(String out_batch_no) {this.out_batch_no = out_batch_no;return this;}public InitiateBatchTransferRequest setBatch_name(String batch_name) {this.batch_name = batch_name;return this;}public InitiateBatchTransferRequest setBatch_remark(String batch_remark) {this.batch_remark = batch_remark;return this;}public InitiateBatchTransferRequest setTotal_amount(Integer total_amount) {this.total_amount = total_amount;return this;}public InitiateBatchTransferRequest setTotal_num(Integer total_num) {this.total_num = total_num;return this;}public InitiateBatchTransferRequest setTransfer_detail_list(List<TransferDetailInput> transfer_detail_list) {this.transfer_detail_list = transfer_detail_list;return this;}public InitiateBatchTransferRequest setTransfer_scene_id(String transfer_scene_id) {this.transfer_scene_id = transfer_scene_id;return this;}public InitiateBatchTransferRequest setNotify_url(String notify_url) {this.notify_url = notify_url;return this;}
}

然后直接写接口此处是单笔转账方法:

@RequestMapping("/batchTransfer")@ResponseBodypublic String batchTransfer(String openId, BigDecimal fee) throws Exception {String out_batch_no = PayKit.generateStr();InitiateBatchTransferRequest batchTransferModel = new InitiateBatchTransferRequest().setAppid("APPID").setOut_batch_no(out_batch_no).setBatch_name("转账批次名称").setBatch_remark("批次备注").setTotal_amount(fee.multiply(new BigDecimal("100")).intValue()).setTotal_num(1).setNotify_url("回调地址").setTransfer_detail_list(Collections.singletonList(new TransferDetailInput().setOut_detail_no(PayKit.generateStr()).setTransfer_amount(fee.multiply(new BigDecimal("100")).intValue()).setTransfer_remark("明细备注").setOpenid(openId)));log.info("发起商家转账请求参数 {}", JSONUtil.toJsonStr(batchTransferModel));IJPayHttpResponse response = WxPayApi.v3(RequestMethodEnum.POST,WxDomainEnum.CHINA.toString(),TransferApiEnum.TRANSFER_BATCHES.toString(),"商户号",getSerialNumber(),null,"apiclient_key.pem",JSONUtil.toJsonStr(batchTransferModel));log.info("发起商家转账响应 {}", response);if (response.getStatus() == 200) {JSONObject jsonObject = JSONObject.parseObject(JSONUtil.toJsonStr(response.getBody()));System.out.println("batch_status:" + jsonObject.getString("batch_status"));System.out.println("batch_id:" + jsonObject.getString("batch_id"));//处理你的业务return "OK";} else {return "ERROR";}}

上述代码块中用到的方法getSerialNumber()如下:

private String getSerialNumber() {if (StrUtil.isEmpty(serialNo)) {// 获取证书序列号X509Certificate certificate = PayKit.getCertificate("apiclient_cert.pem");if (null != certificate) {serialNo = certificate.getSerialNumber().toString(16).toUpperCase();// 提前两天检查证书是否有效boolean isValid = PayKit.checkCertificateIsValid(certificate, "商户号", -2);log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));}}System.out.println("serialNo:" + serialNo);return serialNo;}

 上述代码注意点, 用到的证书有两个:apiclient_cert.pem,apiclient_key.pem都是由商户API证书中下载所得

因为用户在调用转账接口后, 返回的订单状态都是已受理, 故而设置了回调地址, 起到监听管理员通过转账请求后刷新订单的作用

注意:由于回调中微信返回的为密文解密后才能使用, 所需需要验签和解密的过程,其中需要用到APIv3的密钥和平台证书

由于平台证书不能直接下载,此处先介绍证书的下载方法:
1、下载微信提供的CertificateDownloader.jar 

(下载地址:Releases · wechatpay-apiv3/CertificateDownloader (github.com))
2、编辑指令:java -jar CertificateDownloader.jar -k {apiV3key} -m {商户号} -f {apiclient_key.pem的物理路径} -s {证书序列号} -o {平台证书的导出路径}

注意的是其中的证书序列号为商户API证书中显示的证书序列号 (替换关键字即可,指令中不需要{})

3、编写回调方法如下:

 @RequestMapping(value = "/TransferNotify", method = {RequestMethod.POST, RequestMethod.GET})@ResponseBodypublic String TransferNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {Map<String, String> map = new HashMap<>(12);try {String timestamp = request.getHeader("Wechatpay-Timestamp");String nonce = request.getHeader("Wechatpay-Nonce");String serialNo = request.getHeader("Wechatpay-Serial");String signature = request.getHeader("Wechatpay-Signature");log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);String result = HttpKit.readData(request);log.info("支付通知密文 {}", result);// 需要通过证书序列号查找对应的证书, verifyNotify中有验证证书的序列号String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,"APIv3密钥", "通过指令导出的平台证书路径");log.info("支付通知明文 {}", plainText);if (StrUtil.isNotEmpty(plainText)) {JSONObject jsonObject = JSONObject.parseObject(plainText);System.out.println("batch_id:"+jsonObject.getString("batch_id"));System.out.println("batch_status:"+jsonObject.getString("batch_status"));response.setStatus(200);map.put("code", "200");map.put("message", "SUCCESS");} else {response.setStatus(500);map.put("code", "ERROR");map.put("message", "签名错误");}response.setHeader("Content-type", ContentType.JSON.toString());response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));response.flushBuffer();} catch (Exception e) {log.error("系统异常", e);}return null;}

到此微信支付的商家转账到零钱就结束了, 麻烦集中在用到的证书比较多容易混淆,其次就是平台证书导出时的问题!

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

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

相关文章

【办公软件】Excel如何开n次方根

在文章&#xff1a;【分立元件】电阻的基础知识中我们学习电阻值、电阻值容差标注相关标准。知道了标准将电阻值标准数列化。因此电阻值并非1Ω、2Ω、3Ω那样的整数&#xff0c;而是2.2Ω、4.7Ω那样的小数。 这是因为电阻值以标准数(E系列)为准。系列的“E”是Exponent(指数)…

react vant 在使用dialog.confirm取消报错 Uncaught (in promise) undefined

项目场景&#xff1a; 在使用react做移动端开发时&#xff0c;需要使用Dialog.confirm确认框来做弹框选项&#xff0c;这是在操作中非常常用的一种场景。 问题描述 在列表中&#xff0c;使用弹框时&#xff0c;点击取消时&#xff0c;语法报错&#xff1b;导致后面再触发弹框…

【RabbitMQ之一:windows环境下安装RabbitMQ】

目录 一、下载并安装Erlang1、下载Erlang2、安装Erlang3、配置环境变量4、验证erlang是否安装成功 二、下载并安装RabbitMQ1、下载RabbitMQ2、安装RabbitMQ3、配置环境变量4、验证RabbitMQ是否安装成功5、启动RabbitMQ服务&#xff08;安装后服务默认自启动&#xff09; 三、安…

作业0903

1.封装栈 #include <iostream>using namespace std;class myStack { private:int size; // 大小int capacity;int *ptr;int top; // 栈顶下标 public:// 无参构造函数myStack():size(0), top(-1), capacity(10) {ptr new int[capacity];}// 有参构造函数myStack(in…

Linux Debian12使用flameshot或gnome-screenshot和ImageMagick垂直合并多张图片后组成一张滚动长图

在发布博客&#xff0c;有时需要滚动截长图&#xff0c;虽然在windows系统有滚动截长图的工具&#xff0c;例如&#xff1a;FastStone Capture等&#xff0c;但是Linux Debian系统&#xff0c;这种滚动截长图的工具没有找到合适的。经过自己筛选验证&#xff0c;发现Linux Debi…

基于Bert-base-chinese训练多分类文本模型(代码详解)

目录 一、简介 二、模型训练 三、模型推理 一、简介 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;是基于深度学习在自然语言处理&#xff08;NLP&#xff09;领域近几年出现的、影响深远的创新模型之一。在BERT之前&#xff0c;已…

Allure报告下载不同格式的文件

支持类型&#xff1a; class AttachmentType(Enum):def __init__(self, mime_type, extension):self.mime_type mime_typeself.extension extensionTEXT ("text/plain", "txt")CSV ("text/csv", "csv")TSV ("text/tab-sep…

搭建 xxl-job 调度中心

文章目录 1、初始化“调度数据库”2、修改“调度中心”配置3、打包运行”调度中心“ 1、初始化“调度数据库” 请下载项目源码并解压&#xff0c;获取 “调度数据库初始化SQL脚本” 并执行即可。 “调度数据库初始化SQL脚本” 位置为&#xff1a;/xxl-job/doc/db/tables_xxl_j…

【Qt】QLCDNumber | QProgressBar | QCalendarWidget

文章目录 QLCDNumber —— 显示数字QLCDNumber 的属性QLCDNumber 的使用 QProgressBar —— 进度条QProgressBar 的属性创建一个进度条修改为 红色的进度条 QCalendarWidget —— 日历QCalendarWidget 的属性QCalendarWidget 的使用 QLCDNumber —— 显示数字 QLCDNumber 的属…

C++基础多态

目录 学习内容&#xff1a; 1. 多态 1.1 多态的实现 1.2 函数重写&#xff08;override&#xff09; 1.3 虚函数 1.4 使用多态实现的实例 1.5 虚函数的底层实现 1.6 重载&#xff08;voerload&#xff09;、重写&#xff08;override&#xff09;和隐藏&#xff08;h…

DeepWalk【图神经网络论文精读】笔记

链接: DeepWalk【图神经网络论文精读】_哔哩哔哩_bilibili [内容总结::] - deep walk 解决图嵌入问题&#xff1a;将结点压缩成低维向量随机游走&#xff08;类似NLP生成句子&#xff09; 优点与缺点: 相关学习资料 - word2vec 开山必读论文 - DeepWalk 论文阅读 - 代…

若楠带你初识OpenCV(1)-- 视频、图片基础处理,颜色获取

文章目录 OpenCV一、核心功能二、初识OpenCV1. 安装OpenCV2. 读取图片3. 读取灰度图4. 图片保存5. 视频文件读取6. 区域截取7. 提取RGB通道颜色8. 合并颜色通道 总结 OpenCV OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学…

MES 系统中工艺管理--工艺指令管理

一.生产系统柔性&#xff0c;高复用性需求。 工艺路线---------生产线 工序------工位 工艺指令-----具体工步 二.工艺指令分类 1、工艺要求支持配置指令、站点后在过点时&#xff0c;自动调用指令执行。物料、工步、人员作为预留设置&#xff1b; 2、指令主要分ABCD四类&…

Git基础教程:掌握版本控制的秘密

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;C从入门到精通 目录 &#x1f680; 什么是Git &#x1f680; 在本系列博客中所实现的目标 一&#xff1a; &#x1f525; Git 初识 二&#xff1a; &#x1f525; Git 安装 &#x1f34a; Linux-c…

GAMES202——作业4 Kulla-Conty BRDF(BRDF的预计算、重要性采样)

目录 任务 实现 预计算E() 预计算Eavg Bonus1&#xff1a;重要性采样 在实时渲染中使用预计算数据 结果 任务 完成 Kulla-Conty BRDF 模型&#xff0c;关键在于计算 BRDF 的补偿项 f ms &#xff0c;而 f ms 的计算需要 E ( ) 和 E avg 两个前置变量。 1.预计算E() …

【pgAdmin4】创建/删除:数据库Database和数据库表Table

目录 0.环境 1.简介 2.详细步骤 1&#xff09;创建数据库 法一&#xff1a;UI界面创建 法二&#xff1a;sql语句创建数据库 2&#xff09;创建数据库表 查看数据库表 查看数据库表内容 法一&#xff1a;UI界面创建数据库表 法二&#xff1a;sql语句创建数据库表 3&…

快专利与慢专利:速度与质量的天平

在当今快速发展的科技时代&#xff0c;专利成为了创新成果的重要保护手段。然而&#xff0c;不同的创新有着不同的节奏&#xff0c;由此也产生了“快专利”与“慢专利”之分。快专利以其迅速的申请和应用&#xff0c;为创新者抢占市场先机&#xff1b;慢专利则凭借深度的研发和…

【Redis之一:下载安装Redis】

Redis下载与安装 一、下载 Redis 安装包1、 Windows 安装包下载 二、安装Redis1、 Windows 安装Redis 三、配置 Redis1、 Windows 中配置 Redis&#xff08;1&#xff09;配置访问密码&#xff08;2&#xff09;重启 Redis 服务 三、访问 Redis1、命令行访问 Redis&#xff08;…

【福利】最新可用!谷歌搜索和谷歌学术的镜像网站

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 内容来自&#xff1a;https://www.80srz.com/posts/1633.html 谷歌搜索镜像 Google搜索镜像1&#xff1a;https://g.savalone.com/ Google搜索镜像2&…

Python基础笔记

一、python基础1.1 基础知识1.1.1 注释 注释&#xff1a;在程序中对程序代码进行解释说明的文字。 作用&#xff1a;注释不是程序&#xff0c;不能被执行&#xff0c;只是对程序代码进行解释说明&#xff0c;让别人可以看懂程序代码的作用&#xff0c;能够大大增强程序的可读性…