Java微信支付对帐,微信账单下载并读取到实体Bean,并保存至数据库

最近公司的项目需要微信对帐功能,这里展示了简单的微信账单下载并读取到数据库方法,有问题或者更好的想法的可以在评论区交流哟。

一、依赖

<!-- 微信支付 -->
<dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-java</artifactId><version>0.2.12</version>
</dependency><!-- csv处理 -->
<dependency><groupId>com.opencsv</groupId><artifactId>opencsv</artifactId><version>5.9</version>
</dependency>

二、参考链接

https://pay.weixin.qq.com/docs/merchant/products/bill-download/development.html

https://opencsv.sourceforge.net/

三、详解

  1. 下载微信账单
    public boolean downloadTradeBill(String time, String filePath) {// time = "2023-11-16"; 事例// 获取交易账单RSAAutoCertificateConfig config = this.configManager.getConfig("payOrder");BillDownloadServiceExtension service = new BillDownloadServiceExtension.Builder().config(config).build();GetTradeBillRequest request = new GetTradeBillRequest();request.setBillDate(time);request.setBillType(BillType.ALL);request.setTarType(TarType.GZIP);DigestBillEntity bill = service.getTradeBill(request);try (InputStream inputStream = bill.getInputStream()) {// 使用有缓存的 BufferedOutputStreamtry (BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(filePath))) {// 处理大文件时,常用的缓冲区大小为 8192 或 16384。// 不过,最佳缓冲区大小可能取决于具体的硬件和系统配置。byte[] buffer = new byte[16384];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}}} catch (IOException e) {throw new RuntimeException(e);}// 验证数据流中已读取数据的摘要if (bill.verifyHash()) {// 账单是完整准确,可以开启后续操作,例如完成每日对账。log.info("微信账单下载验证成功!");return true;} else {// 账单不完整或者被篡改,应清理之前保存的文件try {Path path = Paths.get(filePath);Files.delete(path);} catch (IOException e) {log.error(e.toString());}return false;}}

注意:RSAAutoCertificateConfig config = this.configManager.getConfig(“payOrder”);

请根据自身项目按照实际获取微信支付的RSAAutoCertificateConfig 。

注意:下载的文件格式为UTF-8 BOM 这里有坑,请一定小心

  1. 过滤微信账单的无用部分(完整详细账单格式请见:https://pay.weixin.qq.com/docs/merchant/products/bill-download/format-trade.html)
    在这里插入图片描述
	// 微信账单去除最后无用部分(最后两行汇总信息)private void removeUselessParts(String inputFilePath, String outputFilePath) {try (BufferedReader reader = new BufferedReader(new FileReader(inputFilePath, StandardCharsets.UTF_8));FileWriter writer = new FileWriter(outputFilePath, StandardCharsets.UTF_8)) {String line = null, line1 = null, line2 = null, line3 = null;int count = 0;while ((line = reader.readLine()) != null) {line3 = line2;line2 = line1;line1 = line;if (count < 2) {count++;} else {writer.write(line3 + "\n");}}} catch (IOException e) {logger.error(e.toString());}}
  1. 读取微信账单

微信支付账单实体Bean(可以按需获取,本例只引用了部分)

public class Bill extends BaseEntity {// 交易时间@CsvBindByPosition(position = 0, capture = "`(.*)")@CsvDate("yyyy-MM-dd HH:mm:ss")private Date tradingHours;// 微信订单号@CsvBindByPosition(position = 5, capture = "`(.*)")private String weChatOrderNumber;// 商户订单号@CsvBindByPosition(position = 6, capture = "`(.*)")private String merchantOrderNumber;// 交易状态@CsvBindByPosition(position = 9, capture = "`(.*)")private String transactionStatus;// 应结订单金额@CsvBindByPosition(position = 12, capture = "`(.*)")private String payableOrderAmount;// 微信退款单号@CsvBindByPosition(position = 14, capture = "`(.*)")private String weChatRefundNumber;// 商户退款单号@CsvBindByPosition(position = 15, capture = "`(.*)")private String merchantRefundNumber;// 退款金额@CsvBindByPosition(position = 16, capture = "`(.*)")private BigDecimal refundAmount;// 订单金额@CsvBindByPosition(position = 24, capture = "`(.*)")private BigDecimal amount;// 申请退款金额@CsvBindByPosition(position = 25, capture = "`(.*)")private BigDecimal requestRefundAmount;
}

读取微信账单csv文件

	public void readAndSaveWeChatTradeBill(String filePath) {InputStreamReader reader = null;try {reader = new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8);CsvToBean<WeChatTradeBill> csvToBean = new CsvToBeanBuilder<WeChatTradeBill>(reader).withType(WeChatTradeBill.class).withSkipLines(1).build();// 使用迭代器读取并分步保存int count = 0;List<WeChatTradeBill> list = new ArrayList<>();for (WeChatTradeBill next : csvToBean) {count++;if (count % 100 == 0) {weChatTradeBillDao.saveAll(list);list = new ArrayList<>();} else {list.add(next);}}if (!CollectionUtils.isEmpty(list)) {weChatTradeBillDao.saveAll(list);}} catch (FileNotFoundException e) {throw new RuntimeException(e);} finally {try {assert reader != null;reader.close();} catch (IOException e) {logger.error(e.toString());}}}

四、完整参考

public void autoImportWeChatTradeBill(String date) {String time;if (date == null) {LocalDate threeDayAgo = LocalDate.now().minusDays(3L);time = threeDayAgo.format(DateTimeFormatter.ISO_LOCAL_DATE);} else {time = LocalDate.parse(date, DateTimeFormatter.ISO_DATE).format(DateTimeFormatter.ISO_DATE);}String downloadFilePath = System.getProperty("user.dir") + "\\" + time + "-wechat.csv";String updateFilePath = System.getProperty("user.dir") + "\\" + time + "-wechat-update.csv";// 尝试下载账单文件,并且去除最后无用部分int count = 0;while (count < 10) {count++;boolean b = wechatUtils.downloadTradeBill(time, downloadFilePath);if (b) {break;} else if (count >= 10) {logger.error("多次尝试,账单仍下载失败!!!");}}this.removeUselessParts(downloadFilePath, updateFilePath);// 解决this自调用事务失效问题WeChatTradeBillServiceImpl bean = applicationContext.getBean(WeChatTradeBillServiceImpl.class);bean.readAndSaveWeChatTradeBill(updateFilePath);// 删除之前下载的账单文件。removeOldDownloadFile(downloadFilePath);removeOldDownloadFile(updateFilePath);}// 删除下载的微信账单文件
private void removeOldDownloadFile(String filePath) {try {Path path = Paths.get(filePath);Files.delete(path);} catch (IOException e) {logger.error(e.toString());}
}

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

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

相关文章

全网最新最全的自动化测试教程:python+pytest接口自动化-测试函数、测试类/测试方法的封装

前言 在pythonpytest 接口自动化系列中&#xff0c;我们之前的文章基本都没有将代码进行封装&#xff0c;但实际编写自动化测试脚本中&#xff0c;我们都需要将测试代码进行封装&#xff0c;才能被测试框架识别执行。 例如单个接口的请求代码如下&#xff1a; import reques…

深入理解JVM虚拟机第二十七篇:详解JVM当中InvokeDynamic字节码指令,Java是动态类型语言么?

😉😉 学习交流群: ✅✅1:这是孙哥suns给大家的福利! ✨✨2:我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 🥭🥭3:QQ群:583783824 📚📚 工作微信:BigTreeJava 拉你进微信群,免费领取! 🍎🍎4:本文章内容出自上述:Sp…

YOLO5Face算法解读

论文&#xff1a;YOLO5Face: Why Reinventing a Face Detector 链接&#xff1a;https://arxiv.org/abs/2105.12931v1 机构&#xff1a;深圳神目科技&LinkSprite Technologies&#xff08;美国&#xff09; 开源代码&#xff1a;https://github.com/deepcam-cn/yolov5-face…

如何定位当生产环境CPU飙升的时候的问题

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、排查思路 二、预防CPU飙升 三、总结 前言 在当今的信息化时代&#xff0c;计算机系统在各行各业都发挥着重要的作用。然而&a…

DeepStream--测试PCB-Defect-Detection

GitHub - clintonoduor/PCB-Defect-Detection-using-Deepstream: PCB defect detection using deepstream & YoloV5我参考了了这个代码&#xff0c;作者基于YoloV5&#xff0c;训练一个电路板检测的模型&#xff0c;训练数据集来自https://robotics.pkusz.edu.cn/resources…

BearPi Std 板从入门到放弃 - 后天篇(1)(I2C1 读取 光照强度)

简介 基于 BearPi Std 板从入门到放弃 - 引气入体篇&#xff08;5&#xff09;(printf打印到串口), 通过I2C接口&#xff0c;读取光照强度并打印到串口; 开发板 &#xff1a; Bearpi Std(小熊派标准板) 主芯片: STM32L431RCT6 LED : PC13 \ 推挽输出即可 \ 高电平点亮 串口: U…

SpringBoot整合RocketMQ

SpringBoot整合RocketMQ 文章目录 SpringBoot整合RocketMQ下载安装SpringBoot整合RocketMQ导坐标改配置实现消息生产与消费 下载安装 教程地址&#xff1a;https://www.bilibili.com/video/BV15b4y1a7yG/?p132&spm_id_from333.1007.top_right_bar_window_history.content.…

11. 哈希冲突

上一节提到&#xff0c;通常情况下哈希函数的输入空间远大于输出空间&#xff0c;因此理论上哈希冲突是不可避免的。比如&#xff0c;输入空间为全体整数&#xff0c;输出空间为数组容量大小&#xff0c;则必然有多个整数映射至同一桶索引。 哈希冲突会导致查询结果错误&#…

大数据技术学习笔记(四)—— HDFS

目录 1 HDFS 概述1.1 HDFS 背景与定义1.2 HDFS 优缺点1.3 HDFS 组成架构1.4 HDFS 文件块大小 2 HDFS的shell操作2.1 上传2.2 下载2.3 HDFS直接操作 3 HDFS的客户端操作3.1 Windows 环境准备3.2 获取 HDFS 的客户端连接对象3.3 HDFS文件上传3.4 HDFS文件下载3.5 HDFS删除文件和目…

最强AI之风袭来,你爱了吗?

2017年&#xff0c;柯洁同阿尔法狗人机大战&#xff0c;AlphaGo以3比0大获全胜&#xff0c;一代英才泪洒当场...... 2019年&#xff0c;换脸哥视频“杨幂换朱茵”轰动全网&#xff0c;时至今日AI换脸仍热度只增不减&#xff1b; 2022年&#xff0c;ChatGPT一经发布便轰动全球&a…

【hacker送书第8期】Java从入门到精通(第7版)

第8期图书推荐 内容简介编辑推荐作者简介图书目录参与方式 内容简介 《Java从入门到精通&#xff08;第7版&#xff09;》从初学者角度出发&#xff0c;通过通俗易懂的语言、丰富多彩的实例&#xff0c;详细讲解了使用Java语言进行程序开发需要掌握的知识。全书分为4篇共24章&a…

nginx对多个服务器的高可用,容易出现鉴权失败

高可用简单测试正常&#xff0c;但是出现高概率401鉴权错误 抓包发现&#xff0c;确实是401 &#xff0c; 而鉴权是两次交互&#xff1a; 抓包发现鉴权到不同服务器上了&#xff0c;导致鉴权没有完成。 此时就需要我们的ip_hash,把同一IP地址的请求,都分配给同一台后端服务器&…

【UE5】使用场系统炸毁一堵墙

效果 步骤 1. 新建一个空白项目 2. 新建一个Basic关卡&#xff0c;然后添加一个第三人称游戏和初学者内容包到内容浏览器 3. 在场景中添加一堵墙 4. 选项模式选择“破裂” 点击新建 新建一个文件夹用于存储几何体集 点击“统一” 最小和最大Voronoi点数都设置为100 点击“破…

cmd查看进程信息 终止进程

cmd查看进程信息 终止进程 1、cmd查看进程信息2、终止进程 1、cmd查看进程信息 tasklist命令 描述: 该工具显示在本地或远程机器上当前运行的进程列表。 tasklist /?查看本机所有进程列表 tasklist /V根据进程名 查看jmeter进程 tasklist /V |findstr /i jmeter2、终止进程…

1+x网络系统建设与运维(中级)-练习3

一.设备命名 AR1 [Huawei]sysn AR1 [AR1] 同理可得&#xff0c;所有设备的命名如上图所示 二.VLAN LSW1 [LSW1]vlan 10 [LSW1-vlan10]q [LSW1]int g0/0/1 [LSW1-GigabitEthernet0/0/1]port link-type access [LSW1-GigabitEthernet0/0/1]port default vlan 10 [LSW1-GigabitEt…

避免20种常见Selenium自动化测试异常,让你的测试更加稳定和可靠!

常见的Selenium异常 以下是所有Selenium WebDriver代码中可能发生的一些常见Selenium异常。 1、ElementClickInterceptedException 由于以某种方式隐藏了接收到click命令的元素&#xff0c;因此无法正确执行Element Click命令。 2、ElementNotInteractableException 即使目…

【Qt开发流程】之事件过滤器及sendEvent和postEvent

描述 事件过滤器(Event Filter)是Qt中一个强大的事件处理机制&#xff0c;它可以在对象接收到事件之前截获事件&#xff0c;并进行自定义处理。事件过滤器可以在不修改对象自身代码的前提下&#xff0c;对其进行事件处理和拦截。 事件过滤器的使用过程如下&#xff1a; 创建一…

C++ 文件操作之配置文件读取

C 文件操作之配置文件读取 在项目应用时常常会涉及一些调参工作&#xff0c;如果项目封装成了.exe或者.dll&#xff0c;那么频繁调参多次编译是一件十分低效的事情&#xff0c;如果代码算法或者逻辑是一定的&#xff0c;那么参数完全可以通过读入配置文件来获取之前在用C - op…

界面组件DevExpress Reporting v23.1新版亮点 - UX功能增强

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表 界面组件DevExpress Reporting v23.1已于前段时间…

Db2的Activity event monitor在Db2 MPP V2上收集ROWS_INSERTED信息

注&#xff1a;本文不是讲解Db2 Activity event monitor&#xff0c;只是一个用法实践。要了解Activity event monitor&#xff0c;请参考 https://www.ibm.com/docs/en/db2/11.5?topicevents-activity-event-monitoring 。 环境 Red Hat Enterprise Linux release 8.8 (Oot…