Compare commits

..
225 Commits
Author SHA1 Message Date
Binary Wang 42f727cd41 🔖 发布 4.8.0 正式版本 2026-01-03 23:36:12 +08:00
Copilot 7c6dbf15e4 🎨 #3827【企业微信】修复群聊变更事件MemChangeList字段命名规范问题
Publish to Maven Central / build-and-publish (push) Has been cancelled
2026-01-03 16:45:03 +08:00
夏沫浅微凉 db15aec8de 🐛 #3825 【微信支付】修复初始化api v3请求时证书序列号值生成条件错误的问题 2025-12-27 21:10:39 +08:00
Copilot 6504f5d82c 🆕 #3823 【企业微信】添加获取应用管理员列表的接口 2025-12-24 16:14:20 +08:00
Copilot 912ba354e9 🎨 #3821 【企业微信】修复 WxCpRedisConfigImpl.getWebhookKey() 方法无限递归调用的问题 2025-12-24 16:12:56 +08:00
Charon-张同学 f00a71965a 🎨 修改微信医保支付模块的规范性问题,主要涉及字段命名标准化、数据类型调整和 API 方法签名优化
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-12-24 15:47:54 +08:00
yanglegetuo c2d0cf8d4e 🆕 #3818 【小程序】 新增设备组相关的 API 接口 2025-12-24 10:05:07 +08:00
Copilot 8e760a972d 🎨 #3654 【开放平台】消息路由处理程序增加对小程序的支持 2025-12-22 09:37:25 +08:00
Copilot b601b557f9 🎨 支付回调结果解析时提供必要的检测报错判断 2025-12-21 21:57:27 +08:00
Copilot 40428bc7cf 📝 添加微信开放平台小程序审核额度管理指南 2025-12-21 21:54:43 +08:00
Copilot e3463a0adf 🎨 #3686 【微信支付】付款码支付接口添加服务商模式支持 2025-12-21 20:27:44 +08:00
Copilot f249450dbe 🎨 #3798 【微信支付】微信支付下单接口结果JsapiResult类中添加prepayId字段 2025-12-21 18:03:36 +08:00
Copilot b0d9c6cc76 🆕 #3717 【微信支付】商户转账新增免确认收款授权模式支持
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-12-21 17:49:11 +08:00
Copilot 621b8dc0e4 🆕 #3812 【小程序】实现用工关系API支持 2025-12-21 17:31:53 +08:00
Copilot 58cdef951f 🆕 #3811 【小程序】添加小游戏道具直购(present_goods)API的支持 2025-12-20 20:08:30 +08:00
Copilot 14537479c7 🎨 #3813 【微信支付】修复委托代扣协议字段名拼写错误 2025-12-20 20:07:04 +08:00
Copilot 3b8d0a8814 🆕 #3814 【微信支付】增加实名验证的接口 2025-12-20 17:23:55 +08:00
Sexy Six c8cdfb56e1 🆕 #3816 【微信支付】增加 V3 医保相关接口的完整支持 2025-12-20 17:20:45 +08:00
Copilot 81816456c1 🆕 #3815 【企业微信】增加智能机器人消息接收和主动发送功能 2025-12-20 17:18:22 +08:00
Binary Wang b9f49094c0 修改中文输出和单元测试要求
更新了中文输出要求,添加了单元测试代码的说明。
2025-12-20 11:54:34 +08:00
舍出 b56eddd47b 🎨 #3800 【微信支付】小微商家进件 API 进行参数结构调整 2025-12-15 15:30:31 +08:00
hyf1844 ef5f28cb28 🎨 #3806 【视频号】微信小店订单详情接口新增会员权益等优惠金额字段 2025-12-11 16:32:39 +08:00
Copilot d26172e393 🎨 #3802 【小程序】修复 WxMaExpressOrderCargo 几个字段类型以支持小数值 2025-12-10 14:27:27 +08:00
buaazyl c777dc32a8 🎨 #3799 【小程序】发货信息管理功能补充消息推送字段,支持订单发货和结算事件的完整信息接收 2025-12-10 10:07:36 +08:00
Copilot c0db88091f 🎨 #3791 【微信支付】特约商户进件接口添加了小微商户(个体经营者)的数据字段支持
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-12-05 16:28:23 +08:00
Copilot 85bd27424d 🎨 #3795 【小程序】客服消息API新增了 aimsgcontext 字段,用于AI消息上下文关联 2025-12-05 16:20:18 +08:00
Copilot ddcdf658cf 🐛 #3797 【微信支付】修复商家转账API路径错误,移除多余的operation部分 2025-12-05 16:19:06 +08:00
Copilot 4e46486f2c 🎨 #3598 【企业微信】 会话存档接口添加对音视频通话(voiptext)消息类型的支持 2025-12-04 19:43:15 +08:00
Copilot 219a8f4f36 🎨 #3620 【小程序】修复同城配送API签名错误问题(添加RSA私钥序列号到签名payload和请求头) 2025-12-04 19:40:03 +08:00
Copilot cd4317ab3e 🎨 #3384 【公众号】为 starter 添加 HttpComponents (httpclient5) 支持 2025-12-04 19:38:10 +08:00
Copilot 085125960b 🎨 #3608 【微信支付】修复 fullPublicKeyModel 配置在 Spring Boot Starter 和 Solon 插件中无效的问题 2025-12-03 17:27:24 +08:00
Copilot 524762704c 🆕 #3524 【小程序】添加多端登录 code2VerifyInfo 接口的支持 2025-12-03 17:25:53 +08:00
Copilot f7a196c129 🎨 修复支付公钥模式下回调验证serialNumber空指针异常 2025-12-02 12:08:01 +08:00
Copilot 3bf3595dc1 🎨 修复 WxCpApprovalWorkflowDemo.java 的兼容性和编译错误 2025-12-02 12:03:03 +08:00
Copilot 4d0617f7bf 🐛 #3515 修复OkHttp请求方式时代理认证头设置错误的问题 2025-12-02 11:24:40 +08:00
Binary Wang fd3bbde725 🔖 发布 4.7.9.B 测试版本
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-11-28 22:37:15 +08:00
Binary Wang 84e70febdf update agent description
更新代理名称和描述为中文,并强调提交信息也需使用中文。
2025-11-28 21:54:48 +08:00
Copilot 155f3f778f 🎨 #3570 【小程序】添加微信云托管支持 2025-11-28 21:38:57 +08:00
Copilot 26f5887e22 📝 为现有的企业微信流程审批功能添加完整的使用文档
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-11-28 11:52:33 +08:00
Copilot 23a2e18f1c 🆕 #3682 【企业微信】新增智能机器人的接口支持 2025-11-28 11:50:50 +08:00
Copilot 8f20f3baba 🆕 #3678 【小程序】新增客服管理相关接口 2025-11-28 11:49:15 +08:00
Copilot 93a2fa701a 🆕 #3519 【小程序】实现交易投诉的相关接口 2025-11-28 11:46:10 +08:00
Copilot 1f4ed68750 🎨 #3750 【微信支付】修复 V2 支付回调签名验证失败的问题 2025-11-28 11:29:22 +08:00
Copilot c4f383462e 🆕 #3737 【微信支付】增加V3服务商申请退款的接口 2025-11-28 11:26:46 +08:00
Copilot 03114b9900 🎨 #3753 【微信支付】添加商家转账用户授权免确认模式相关接口 2025-11-28 11:23:05 +08:00
Copilot f6d9e8ba4d 🎨 #3738 【微信支付】修复V3新商户完全公钥模式下publicKey为空的问题 2025-11-28 11:20:51 +08:00
Copilot 1da6cf56ff 🎨 #3755 【企业微信】修复会话存档SDK重复初始化导致接口超限问题 2025-11-28 11:19:38 +08:00
Copilot e655a33956 🎨 #3752 修复 Gson 在 Java 9+ 环境下反射访问 java.io.File#path 字段失败的问题 2025-11-28 11:17:33 +08:00
Copilot 9940546956 🐛 #3675 【小程序】修复退货组件 API 接口请求方法错误的问题 2025-11-28 11:15:41 +08:00
chu 1bd50d4d2f 🆕 #3770 【视频号】新增售后单商家协商、换货发货与拒绝发货等接口 2025-11-28 10:08:55 +08:00
Copilot 8e46da5003 🎨 #3683 【开放平台】修改component_verify_ticket 的有效时间为12小时 2025-11-27 23:20:04 +08:00
Dell Well b1e7cd2cd7 🐛 #3664: 【微信支付】修复微信支付分订单接口提示“商户暂无权限使用此服务” 的问题 2025-11-27 23:16:49 +08:00
hyf1844 7fcd1ed5b3 🎨 #3767 【视频号】微信小店订单详情接口新增会员权益等优惠金额字段 2025-11-27 23:14:16 +08:00
Copilot 21d5f2fdd2 🆕 #3764 【开放平台】添加小程序类目管理 - 获取类目名称信息的接口 2025-11-27 23:06:19 +08:00
Copilot e57b7e1eb5 🎨 #3765 【微信支付】修复从 base64 字符串加载私钥时的双重解码问题 2025-11-27 23:04:11 +08:00
Copilot 833f60c68d 🆕 #3736 【小程序】增加解密群入口敏感数据的方法 2025-11-17 12:01:15 +08:00
Copilot 1922aaaa94 🎨 #3751 【企业微信】提交审批申请接口增加process参数以支持新版的审批流程信息 2025-11-17 11:59:51 +08:00
Copilot 3c440eacb3 🎨 修复 GsonParser 与低版本 Gson 的兼容性问题 2025-11-17 11:11:51 +08:00
Binary Wang b8d2bb345a 📝 添加自定义agent的文档 2025-11-17 11:00:07 +08:00
Binary Wang 730ac24c3f 🎨 优化小程序配置类的javadoc 2025-11-17 10:47:29 +08:00
Copilot ebb9ccdebe 🎨 #3376 【小程序】完善事件消息推送对json数据格式的支持 2025-11-17 10:33:09 +08:00
Copilot 76c7e994a5 🐛 #3700 修复空指针问题
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-11-15 17:14:45 +08:00
Copilot 092e992817 🆕 #3688 【微信支付】 实现预约扣费服务的相关接口 2025-11-15 17:12:21 +08:00
Copilot 69a2ab9cc7 🆕 #3720 【微信支付】实现微信押金支付的相关功能接口 2025-11-15 17:09:29 +08:00
Copilot 0854e4d971 🆕 #3507 【微信支付】实现运营工具-商家转账API相关接口 2025-11-15 17:04:27 +08:00
Copilot 57e12dee29 🐛 #3704 【小程序】修复物流服务-同城配送服务-查询门店余额接口错误的逻辑 2025-11-15 17:03:08 +08:00
Copilot 4d4294707b 🎨 #3728 【微信支付】修复V3支付公钥转账出现的签名验证失败问题 2025-11-15 16:52:49 +08:00
Copilot 9ab64167d5 🎨 #3680 【微信支付】修复PEM格式的私钥和证书处理的问题 2025-11-15 16:47:06 +08:00
helloJetBase-tech 28fac4ec2e 🎨 #3756 【企业微信】修复企业微信 API 回调验签过程中 WxCryptUtil.decrypt 方法可能抛出异常的问题 2025-11-12 13:44:18 +08:00
kongkong b94106fd57 🎨 #3757 【微信支付】修复当只设置 privateCertString 或 PrivateCertContent 时 certSerialNo 没有被正确生成的问题 2025-11-12 13:41:52 +08:00
Copilot d4186c49c1 🆕 #3494 【微信支付】平台收付通提现接口新增回调参数支持及补充日终余额提现API 2025-11-05 10:45:50 +08:00
Copilot bb573afcaf 🎨 #3732 Add Quarkus/GraalVM Native Image support - Fix Random instance initialization issues 2025-11-02 16:30:13 +08:00
troubleMTT e9bc5d0109 🎨 #3746 【企业微信】获取企业已配置的「联系我」列表接口返回值增加next_cursor字段
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-10-30 19:43:35 +08:00
Copilot 738bcf7755 🆕 #3739 【开放平台】补充完善第三方平台小程序快速配置域名的相关接口 2025-10-28 11:59:56 +08:00
Binary Wang de4848b2f7 🎨 规范mp模块的javadoc接口注释文档
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-10-28 11:55:15 +08:00
accept mediocrity b26c786797 🎨 #3745 【微信支付】修复请求微信仿真测试系统时验签密钥接口的 Content-Type 问题 2025-10-28 11:51:26 +08:00
Binary Wang b9b4f00438 📝 Revise development instructions with Chinese translations
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-10-23 11:00:01 +08:00
小付同学 98329b11da 🐛 #3640 【微信支付】修复使用连接池后SSL客户端证书未正确发送导致退款接口报错的问题 2025-10-23 10:12:23 +08:00
Copilot db85c0ab8a 🎨 完善关于开放平台功能的说明文档 2025-10-04 01:47:50 +08:00
Copilot ca567ce310 🆕 #3618 【微信支付】增加境外微信支付的支持 2025-10-04 01:44:56 +08:00
Copilot a6825a62bb 🎨 #3628【企业微信】修复更新用户接口重置用户直属领导字段的问题 2025-10-04 01:39:35 +08:00
Mr.Robot 9fd12b2a09 🎨 WxOpenMessageRouter增加注解ConditionalOnMissingBean 2025-10-04 01:32:23 +08:00
xiaoyun461 10f71234e4 🆕 #3725【企业微信】 增加markdown_v2的消息类型支持 2025-10-04 01:31:24 +08:00
Copilot 9aa2781e68 🎨 #3634 【微信支付】尝试修复服务商模式分账动账通知非法请求、头部信息验证失败的问题 2025-09-27 17:11:32 +08:00
Binary Wang cfe1f6dc95 🔖 发布 4.7.8.B 测试版本
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-09-24 21:55:26 +08:00
Copilot c0edd9fd16 🎨 #3698 【微信支付】 修复字符编码导致的解析报文异常问题 2025-09-24 21:43:30 +08:00
Copilot 1788d9071e 🎨 #3715 企业微信回调消息中的MsgId改为字符串类型 2025-09-24 21:40:27 +08:00
Copilot e6a844ab70 🐛 #3631 修复tryLock和unlock中针对Key的序列化方式不一致导致无法unlock的问题
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-09-23 10:53:09 +08:00
Copilot 6fc17201e1 🎨 #3697 【企业微信】修复自定义工作台enable_webview_click等参数设置无效的问题 2025-09-23 10:40:53 +08:00
Binary Wang ad19f653c7 🎨 优化代码,修复过期方法引用 2025-09-23 10:31:35 +08:00
wangshuai 7018dceb1c :art:【企业微信】企微客户群回调事件添加LastMemVer、CurMemVer字段
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-09-22 16:59:32 +00:00
ihao 399f3648c0 :art:【微信支付】公众号签约缺失执行签名方法,增加非必填参数判断;微信信h5纯签约接口,增加非必填字段判断 2025-09-23 00:58:11 +08:00
graalvm-samples 88bdd4a36e 🆕 #3703 【企业微信】第三方应用基础接口实现 2025-09-23 00:25:39 +08:00
imyzt 213cf6fd67 🐛 #3631 修复tryLock和unlock中针对Key的序列化方式不一致导致无法unlock的问题 2025-09-23 00:24:02 +08:00
hb0730 c8d84da2ab 🎨 #3702 【小程序】多小程序spring starter增加Redis Template支持 2025-09-15 09:45:15 +08:00
dengfengfenganddengfeng 118839a49d 🐛 #3692【小程序】【公众号】修复图片智能裁剪接口请求类型错误的问题
Co-authored-by: dengfeng <dengfeng@huaxincem.com>
2025-09-04 09:19:20 +08:00
水依寒 8447caa75f 🎨 #3694 统一各模块微信接口请求的基础地址字段命名为apiHostUrl,并完善Spring Boot starter配置支持 2025-09-04 09:17:36 +08:00
LiYaoheng 1eefd11e03 🎨 修复文档错误,关于channel-springboot-starter的依赖 2025-09-04 09:13:27 +08:00
tryking123 781798345e 🆕 #3681 【小程序】增加企微客服增删查3个接口 2025-08-31 21:44:24 +08:00
Copilot 0424d75882 🎨 #3323 【企业微信】获取企业所有打卡规则接口增加官方新添加的late_rule等字段 2025-08-08 18:21:59 +08:00
Copilot e61ad44d27 📝 Add comprehensive GitHub Copilot instructions for WxJava SDK development 2025-08-08 18:18:39 +08:00
Copilot dc46d9de75 🎨 #3640 【微信支付】使用HttpClient发送http请求时调整为使用连接池的形式 2025-08-08 17:47:20 +08:00
Copilot bc6fb7b58e 🎨 #3656 【微信支付】 修复平台收付通 - 合单支付 - 关闭订单接口,增加缺少的两个参数
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-08-08 17:40:28 +08:00
Copilot 983e4f1e66 🎨 #3659 【微信支付】新增BaseWxPayV3Result基类,提供rawJsonString字段保存原始API响应 2025-08-08 17:25:40 +08:00
痴货 7ffc1b3719 :new:【开放平台】添加获取换绑管理员 URL 的接口 2025-08-08 06:14:25 +00:00
Binary Wang 8bb4a21598 🎨 #3662 【企业微信】修复获取审批模板详情接口异常的问题:Expected BEGIN_OBJECT but was BEGIN_ARRAY
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-07-30 23:29:59 +08:00
Copilot a881de59a5 🎨 #3567 【企业微信】获取企业所有打卡规则接口调整 2025-07-30 23:10:30 +08:00
Copilot 14f8c8ebc2 🎨 #3655 通过支持现代 TLS 版本修复 SSL 握手失败问题
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-07-25 11:41:06 +08:00
Winnie 875c35e745 🎨 #3660【企业微信】获取会议详情接口响应类补充官方新加的若干字段 2025-07-25 11:35:46 +08:00
Copilot 262a02b606 📝 为微信支付新增商户转账接口添加全面的文档和示例 2025-07-24 16:43:23 +08:00
Copilot 3a1d8075fc 🎨 Fix StackOverflowError in WxCpRedissonConfigImpl and WxCpRedisTemplateConfigImpl toString() methods 2025-07-24 16:39:56 +08:00
Binary Wang 2e952c76c8 🎨 修复错误的变量命名
Publish to Maven Central / build-and-publish (push) Waiting to run
2025-07-24 15:49:15 +08:00
Farahani e5ef34553d 🆕 #3645【小程序】增加虚拟支付的更多接口 2025-07-24 15:29:25 +08:00
匠心 4cdd056a3e 🎨 修复代码缩进格式 2025-07-24 15:18:42 +08:00
痴货 57a6ef1179 🆕 【小程序】增加小程序基本信息通知事件相关的属性
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-07-16 15:06:45 +00:00
痴货 4754a562ca 🎨 调整部分starter模块接口连接的 soTimeout 默认值为 5000毫秒 2025-07-16 15:05:00 +00:00
Binary Wang 62f89987c0 🔖 发布 4.7.7.B 测试版本 2025-07-16 20:05:09 +08:00
痴货 990dbba06b 🎨 【开放平台】重构小程序认证及备案相关接口 2025-07-16 11:47:11 +00:00
痴货 d85e04a72a 🎨 starter模块添加 HttpClient 超时配置 2025-07-16 11:46:38 +00:00
Binary Wang aacfa947be 🎨 统一优化gson adapter类,抽取常量,优化重复代码
Publish to Maven Central / build-and-publish (push) Waiting to run
2025-07-16 13:50:55 +08:00
Ryn 3e4ee57e1c 🎨 #3639 【小程序】修复多账号starter不支持设置数据格式,导致消息解析出错的问题 2025-07-16 13:44:50 +08:00
benben d4cf48d059 🎨 【公众号】删除已下线的新增删除永久图文素材的接口
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-07-12 08:59:11 +00:00
ihao 696ce8621e 🆕 #3636【微信支付】增加微信签约、解约结果通知解析的方法 2025-07-12 16:57:50 +08:00
dependabot[bot] 8c8139533d ⬆️ Bump org.apache.commons:commons-lang3 from 3.10 to 3.18.0 2025-07-12 16:49:40 +08:00
zhfkt 84c69d4900 🎨 Add null check for textJsonElement in WxCpUserGsonAdapter 2025-07-04 15:40:29 +08:00
xuxiancan d52e225626 🎨 #3633【微信支付】创建支付分订单接口请求参数里增加设备信息字段 2025-07-04 15:39:15 +08:00
ihao 686dff6436 🎨 优化微信h5纯签约接口,增加非必填字段判断 2025-07-03 01:55:33 +00:00
Style-lo 92431aabd9 🎨 getConfigKey方法改成public的 2025-07-03 09:53:30 +08:00
Binary Wang 29bc950f92 🎨 为小程序短剧管理服务接口增加接口 2025-07-02 10:35:54 +08:00
Binary Wang 5c74c1d930 🎨 为微信小程序物流退货组件接口增加注释文档 2025-07-02 10:35:54 +08:00
Binary Wang 52d0b2fc1c 🎨 为小程序虚拟支付接口类增加注释文档 2025-07-02 10:35:54 +08:00
Binary Wang 5b816242a4 🎨 优化小程序数据分析接口类的注释文档 2025-07-02 10:35:54 +08:00
Binary Wang a45f0ac048 🎨 优化小程序云开发接口类的注释文档 2025-07-02 10:35:54 +08:00
Binary Wang 4731479b93 🎨 优化小程序接口注释文档 2025-07-02 10:35:54 +08:00
benben cc344f105e 🎨 #3624 【企业微信】企微微盘API相关接口去掉废弃的userId参数 2025-07-02 10:33:56 +08:00
Well 172b96444f 🎨 #3626 【微信支付】创建代金券批次接口新增字段,包括背景色、卡包跳转目标、小程序 appid 与 path等 2025-07-02 10:31:26 +08:00
jinceon b3b8c273c7 🎨 【企业微信】增加“审批申请状态变化回调通知”事件类型 2025-06-28 23:07:36 +08:00
大粽子 b6d489e9c8 📝 修改赞助商信息 2025-06-28 23:07:36 +08:00
zhoushi1andzhoushi1 72266c3aeb 🎨 #3627 【开放平台】小程序三方平台代上传代码提交额外信息对象新增requiredPrivateInfos信息
Co-authored-by: zhoushi1 <qiannanyou9@gmail.com>
2025-06-28 20:57:37 +08:00
altusea ccbfa98864 🎨 添加 Apache HttpComponents Client 5.x 为可选的 http client
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-06-09 14:29:35 +08:00
buaazyl bf35797b91 :art:【小程序】发订阅消息的“43101用户未订阅消息”异常日志调整为debug 2025-06-09 14:28:56 +08:00
buaazyl 41081561b5 :art:【小程序】不再打印发订阅消息的“43101用户未订阅消息”警告日志 2025-06-09 11:19:37 +08:00
Binary Wang 8878f06c1e 🎨 修复单元测试代码
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-06-06 17:07:52 +08:00
Zeyes Lee 22d288f6cd 🎨 #3609 【视频号】微信小店获取售后单接口返回新增换货相关的数据 2025-06-06 16:55:46 +08:00
Binary Wang b0af2c704e 🔖 发布 4.7.6.B 测试版本
Publish to Maven Central / build-and-publish (push) Waiting to run
2025-06-05 23:47:01 +08:00
Binary Wang 320f05e6d6 📝 赞助商表格优化 2025-06-03 12:15:47 +08:00
Binary Wang 4d7fd68fe5 📝 调整两个logo的位置
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-06-03 12:06:48 +08:00
Molzx 388188b694 🎨 【微信支付】调整逻辑:当完全使用公钥模式时,也可从p12证书中读取证书私钥等 2025-06-03 11:53:45 +08:00
altusea ecce9292b2 🎨 初步引入 Apache HttpClient 5.x 2025-06-03 11:52:39 +08:00
msgpo 96a5cc995b 🎨 #3603【企业微信】获取审批申请详情接口 增加说明文字控件的支持 2025-05-29 11:18:12 +08:00
Binary Wang 4d66dd09ca 🎨 修改查看最新版本的地址 2025-05-28 16:22:20 +08:00
阿杆 08e2107667 🎨 #3571【公众号】草稿箱相关接口支持图片文章类型 2025-05-28 15:59:08 +08:00
Binary Wang f71ac2185c 🎨 workflow 里增加 concurrency 设置并发限制 2025-05-22 15:21:39 +08:00
Zeyes Lee 5bde717f8f 🎨 #3594【视频号】微信小店更新售后、订单详情等返回参数,并修改获取售后单列表和获取快递公司列表等接口的参数
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-05-22 15:07:25 +08:00
altusea 8bacc9425e 🎨 修复CloseableHttpClient相关的误用代码 2025-05-22 15:03:27 +08:00
mengyou 3e1a38a696 🎨 #3591【微信支付】修复只设置privateKeyString或者privateKeyContent时私钥初始化失败的问题
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-05-16 20:19:19 +08:00
altusea fefe737803 🎨 #3588 【小程序】短剧媒资列表接口增加新字段media_name_fuzzy 2025-05-15 14:43:07 +08:00
SynchPj d0b7a526f6 🎨 #3587【微信支付】支持完全公钥模式,新增fullPublicKeyModel字段来控制,默认关闭,关闭时走老逻辑,开启时,只加载公钥所需相关配置,避免下载平台证书使灰度切换无法达到100%覆盖 2025-05-14 16:27:29 +08:00
SynchPj 47051bdf31 🎨 #3586 【微信支付】修复资源上传接口使用POST请求Content-Type不正确导致签名错误的问题 2025-05-14 11:54:30 +08:00
Binary Wang f5dd32de86 📝 优化badge展示 2025-05-14 10:44:59 +08:00
altusea d776792bae 🎨 #3575 【视频号】微信小店api官方将要废除finder_id,以promoter_id代替
Publish to Maven Central / build-and-publish (push) Has been cancelled
2025-05-13 22:57:07 +08:00
altusea 1a74e3e3a8 🎨 #3562 【企业微信】发送应用消息接口返回增加unlicenseduser字段 2025-05-13 22:54:28 +08:00
altusea 2762a98279 🎨 #3569 【视频号】微信小店-订单详情查询接口增加参数 2025-05-13 22:52:24 +08:00
altusea 04c162f03a 🎨 #3574 【微信支付】修复商家券available_day_time字段定义错误 2025-05-13 22:50:35 +08:00
Binary Wang 5c2a36c538 🎨 add serialVersionUID for some class 2025-05-13 22:48:25 +08:00
altusea 2c4b5ea128 🎨 #3525 【企业微信】第三方应用配置类提供setProviderSecret 方法 2025-05-13 22:41:15 +08:00
altusea 9a6db34b6a 🎨 #3577 【微信支付】微信分账回退请求接口新增字段:微信订单号transaction_id 2025-05-13 16:18:00 +08:00
Binary Wang 77b90626f3 ⬆️ Bump org.eclipse.jetty:jetty-server 2025-05-13 16:16:17 +08:00
altusea 063fbb7f19 🎨 升级部分依赖版本,优化代码,部分代码增加泛型参数 2025-05-13 15:56:14 +08:00
Binary Wang a7b007f853 📝 修正版本说明文档 2025-05-13 13:08:24 +08:00
SynchPj c91a5a8e22 🎨 【微信支付】修复连接池关闭异常问题 2025-05-13 12:49:46 +08:00
Binary Wang a051587d3e 👷 自动构建迁移到maven central portal 2025-05-13 12:43:51 +08:00
Binary Wang 245cf72104 🎨 增加github action来自动发布版本到maven中央仓库 2025-05-12 12:35:06 +08:00
Binary Wang fb57af7409 🔖 发布 4.7.5.B 测试版本 2025-05-08 23:04:32 +08:00
jimson 88a5bc4f43 🎨 企微客户群回调事件添加MemChangeList字段 2025-05-08 22:15:06 +08:00
Binary Wang dc674ce024 🎨 优化部分javadoc 2025-04-29 12:12:34 +08:00
Binary Wang 854b50bd51 🎨 修复日志代码报错问题 2025-04-29 11:33:58 +08:00
imyzt 2d8d1df00e 🆕 #3320【企业微信】增加异步上传临时素材相关接口 2025-04-29 11:29:09 +08:00
Binary Wang 2279105fef :art: 优化微信支付请求代码,抽取合并重复代码 2025-04-26 11:18:56 +08:00
SynchPj cbb3b24577 🎨 #3553【微信支付】v3请求统一加上Wechatpay-Serial请求头 2025-04-22 11:08:50 +08:00
giveup ddfbee25e1 🐛 #3557 【企业微信】修复agentId数据类型不一致导致的WxCpTpMessageRouterRule.test()方法匹配失败的问题 2025-04-21 10:00:39 +08:00
友人A 6a4ed91ae2 🎨 #3558 【企业微信】修复会话内容存档接口获取解密的聊天数据时文件信息转换出错的问题 2025-04-21 09:58:51 +08:00
西东 59f5a99fda 🆕 添加wx-java-channel-solon-plugin README.md 2025-04-21 09:55:13 +08:00
Henry Heng 3718b499a0 🎨 #3554【企业微信】修复审批通知节点获取不到用户ID的问题 2025-04-16 10:43:55 +08:00
Henry Heng bb76db052d 🎨 #3554【企业微信】修复审批通知节点获取不到用户ID的问题 2025-04-15 19:32:54 +08:00
HerveyHall e16e0e9373 🎨 #3548【微信支付】修复公钥模式下V3接口未设置Wechatpay-Serial请求头导致的验签失败 2025-04-15 15:14:12 +08:00
Holy 89280abd00 🎨 #3547【微信支付】修复验证器未正确初始化导致的v3请求构造异常问题 2025-04-14 11:32:34 +08:00
Binary Wang 0423e6849d 🔖 发布 4.7.4.B 测试版本 2025-04-08 08:39:24 +08:00
zhangrongguang 833ff70680 【企业微信】接待人员管理 添加接待人员/删除接待人员 增加 department_id_list 2025-04-07 09:50:19 +00:00
jimmyjimmy-sw 373c1e65cb 🐛 #3522 【公众号】修复WxMpMapConfigImpl静态属性存储token导致多个实例时出现token没有隔离的情况 2025-04-07 17:47:48 +08:00
谈笑 b44dd2e347 🎨 #3541【企业微信】增加设置WebView型应用在用户工作台展示的参数 2025-04-07 07:01:35 +00:00
谈笑 b6c3d74cba 🆕 #3529 【企业微信】增加批量设置应用在用户工作台展示的数据的接口 2025-04-07 13:05:46 +08:00
cxiaoxifeng 0452a05dd4 🎨 【小程序】修复物流服务查询组件更新物品信息接口的地址 2025-04-07 13:05:46 +08:00
yangmengyu2021 4828a314e9 🎨 #3534 为connectionRequestTimeout设置默认值,避免开发者在虚拟线程中调用框架的httpClient时造成的无限等待 2025-04-07 13:04:33 +08:00
cloudX 3f0b8d4e2b 🎨 #3538 【微信支付】V3接口增加实名支付参数 2025-04-07 13:03:10 +08:00
SynchPj dd407141b0 🎨 #3530 【微信支付】修复未设置平台证书引起的v3请求构造异常 2025-04-07 13:01:53 +08:00
yangmengyu2021 b225afbd68 🎨 #3532 【微信支付】修复支付通知回调解析方法报错的问题 2025-03-23 20:07:01 +08:00
Binary Wang 5604a16ae8 🎨 fix doc 2025-03-23 20:00:52 +08:00
Binary Wang 25309e06ad 🔖 发布 4.7.3.B 测试版本 2025-03-18 12:58:09 +08:00
SynchPj 5ac9922f8d 🎨 #3498【微信支付】服务商模式-兼容公钥模式下请求头序列号以及灰度切换 2025-03-17 10:58:50 +08:00
zhongjq 03790d64bc 🎨 WxMaMessage.allFieldsMap支持json格式数据存放 2025-03-06 20:56:12 +08:00
Lyx Fly 1f0dbcc2aa 🎨 #3516【公众号】修正代理认证请求头设置错误的问题 2025-03-03 15:43:38 +08:00
wzl 404102a4c8 🎨 #3493 【微信支付】修复合单支付combineTransactions接口参数错误问题 2025-03-03 15:42:26 +08:00
raven 5decfcb917 🎨 #3505【微信支付】修复微信支付异步通知请求解析失败问题 2025-03-03 15:40:52 +08:00
sober 44a95578d9 🐛 #3508 【企业微信】获取企业用户信息接口修复用户信息大小写导致的问题 2025-03-03 15:39:23 +08:00
altusea 2bf31411c0 🎨 #3492【视频号】 微信小店获取订单详情接口增加新带货平台Id字段 2025-03-03 15:34:00 +08:00
giveup 71fbc2b1e8 🎨 #3499 【企业微信】配置客户联系「联系我」方式的接口增加 is_exclusive字段 2025-03-03 15:28:35 +08:00
Binary Wang 15b7460d92 🎨 增加新的赞助商logo 2025-03-03 15:25:33 +08:00
zhangruhong 933840e3b2 🎨 消息类增加first/second字段 2025-03-03 15:11:44 +08:00
zhangruhong 5da939647c 🎨 #3500【公众号】消息接受类添加名称审核结果事件推送所需字段 2025-02-19 19:50:49 +08:00
Binary Wang 22ec3f0eca 🎨 增加注释防止误解,同时优化重构代码 2025-02-17 11:12:32 +08:00
je45 410cc9dfd7 🎨 #3490【微信支付】消费者投诉相关接口补充最新增加的一些参数 2025-02-07 21:22:39 +08:00
imyzt 783c89523d 🆕 #3488【企业微信】增加获取企业已配置的「联系我」列表的接口 2025-02-07 19:58:53 +08:00
Binary Wang 3e48dc7f83 🔖 发布 4.7.2.B 测试版本 2025-01-24 22:18:57 +08:00
superffan f3c1422354 :art:【微信支付】spring-boot-starter模块增加公钥ID和证书文件路径等配置项 2025-01-24 21:27:34 +08:00
giveup d65e2f27a9 🎨 WxMpSubscribeMessage实现序列化接口 2025-01-24 21:26:02 +08:00
Neror c3b16228c0 🎨 【微信支付】完善微信商家转账功能API !151 2025-01-21 11:49:38 +00:00
Neror 24ebc91dca 🎨 【微信支付】增加多配置切换功能 2025-01-21 19:36:25 +08:00
GadflyFang 1e003ee571 🎨 修复 94aaff4 引入的错误读取证书的问题 2025-01-21 18:44:33 +08:00
giveup 8e5ee97378 🎨 #3458 【企业微信】家校沟通获取部门列表接口优化,如果部门id为空则获取全量组织架构 2025-01-21 18:41:11 +08:00
julb 704fba4d85 🎨 【微信支付】兼容公钥模式下请求头序列号 !148 2025-01-20 10:52:35 +08:00
Molzx b0daf8428e 🆕 #3479 【小程序】新增订单管理的配置和查询订单配置路径的接口 2025-01-17 12:02:48 +08:00
mrsiu ab1c150feb 🎨 #3478 【企业微信】OA审批接口增加对说明文字控件(control参数为Tips)的支持 2025-01-16 13:50:24 +08:00
潘安 b4b73ad40a 🎨 #3467 【微信支付】商户进件开户意愿接口相关字段调整 2025-01-16 13:47:55 +08:00
allovine be0dd8b692 🆕 #3474 【微信支付】增加2025.1.15正式上线的商户转账新版本的相关接口 2025-01-16 13:46:02 +08:00
900 changed files with 36376 additions and 4584 deletions
+14
View File
@@ -0,0 +1,14 @@
---
# Fill in the fields below to create a basic custom agent for your repository.
# The Copilot CLI can be used for local testing: https://gh.io/customagents/cli
# To make this agent available, merge this file into the default repository branch.
# For format details, see: https://gh.io/customagents/config
name: 全部用中文
description: 需要用中文,包括PR标题和分析总结过程
---
# My Agent
1、请使用中文输出思考过程和总结,包括PR标题,提交commit信息也要使用中文;
2、生成代码时需要提供必要的单元测试代码。
+202
View File
@@ -0,0 +1,202 @@
# Copilot Instruction
请始终使用中文生成 Pull Request 的标题、描述和提交信息
# WxJava - 微信 Java SDK 开发说明
WxJava 是一个支持多种微信平台的完整 Java SDK,包含公众号、小程序、微信支付、企业微信、开放平台、视频号、企点等多种功能模块。
**请始终优先参考本说明,只有在遇到与此内容不一致的意外信息时,才退而使用搜索或 bash 命令。**
## 高效开发指南
### 前置条件与环境准备
- **Java 要求**:JDK 8+(项目最低目标为 Java 8)
- **Maven**:推荐 Maven 3.6+(已验证 Maven 3.9.11)
- **IDE**:推荐使用 IntelliJ IDEA(项目针对 IDEA 优化)
### 引导、构建与校验
克隆仓库后按顺序执行以下命令:
```bash
# 1. 基础编译(请勿中断 - 约需 4-5 分钟)
mvn clean compile -DskipTests=true --no-transfer-progress
# 超时时间:建议设置 8 分钟以上。实际时间:约 4 分钟
# 2. 完整打包(请勿中断 - 约需 2-3 分钟)
mvn clean package -DskipTests=true --no-transfer-progress
# 超时时间:建议设置 5 分钟以上。实际时间:约 2 分钟
# 3. 代码质量校验(请勿中断 - 约需 45-60 秒)
mvn checkstyle:check --no-transfer-progress
# 超时时间:建议设置 3 分钟以上。实际时间:约 50 秒
```
重要时间说明:
- 绝对不要中断任意 Maven 构建命令
- 编译阶段耗时最长(约 4 分钟),原因是项目包含 34 个模块
- 后续构建会更快,因为存在增量编译
- 始终使用 `--no-transfer-progress` 以减少日志噪音
### 测试结构
- **测试框架**:TestNG(非 JUnit)
- **测试文件**:共有 298 个测试文件
- **默认行为**:pom.xml 中默认禁用测试(`<skip>true</skip>`)
- **测试配置**:测试需要通过 test-config.xml 提供真实的微信 API 凭据
- **注意**:没有真实微信 API 凭据请不要尝试运行测试,测试将会失败
## 项目结构与导航
### 核心 SDK 模块(主要开发区)
- `weixin-java-common/` - 通用工具与基础类(最重要)
- `weixin-java-mp/` - 公众号 SDK
- `weixin-java-pay/` - 微信支付 SDK
- `weixin-java-miniapp/` - 小程序 SDK
- `weixin-java-cp/` - 企业微信 SDK
- `weixin-java-open/` - 开放平台 SDK
- `weixin-java-channel/` - 视频号 / Channel SDK
- `weixin-java-qidian/` - 企点 SDK
### 框架集成模块
- `spring-boot-starters/` - Spring Boot 自动配置 starter
- `solon-plugins/` - Solon 框架插件
- `weixin-graal/` - GraalVM 本地镜像支持
### 配置与质量控制
- `quality-checks/google_checks.xml` - Checkstyle 配置
- `.editorconfig` - 代码格式规则(2 个空格等于 1 个制表)
- `pom.xml` - 根级 Maven 配置
## 开发工作流
### 修改代码的流程
1. 修改前务必先构建以建立干净基线:
```bash
mvn clean compile --no-transfer-progress
```
2. 遵循代码风格(由 checkstyle 强制):
- 缩进使用 2 个空格(不要用制表符)
- 遵循 Google Java 风格指南
- 在 IDE 中安装 EditorConfig 插件
3. 增量验证修改:
```bash
# 每次修改后运行:
mvn compile --no-transfer-progress
mvn checkstyle:check --no-transfer-progress
```
### 提交修改前的必须校验
请务必按顺序完成以下校验步骤:
1. 代码风格校验:
```bash
mvn checkstyle:check --no-transfer-progress
# 必须通过 - 约需 50 秒
```
2. 完整清理构建:
```bash
mvn clean package -DskipTests=true --no-transfer-progress
# 必须成功 - 约需 2 分钟
```
3. 文档:为公共方法和类补充或更新 javadoc
4. 贡献规范:遵循 `CONTRIBUTING.md`,Pull Request 必须以 `develop` 分支为目标
## 模块依赖与构建顺序
### 核心模块依赖(构建顺序)
1. `weixin-graal`(GraalVM 支持)
2. `weixin-java-common`(所有模块的基础)
3. 核心 SDK 模块(mp、pay、miniapp、cp、open、channel、qidian)
4. 框架集成(spring-boot-starters、solon-plugins)
### 主要关系模式
- 所有 SDK 模块都依赖于 `weixin-java-common`
- Spring Boot starters 依赖对应的 SDK 模块
- Solon 插件遵循与 Spring Boot starters 相同的依赖模式
- 每个模块都有单账号与多账号配置支持
## 常见任务与命令
### 验证指定模块
```bash
# 构建单个模块(将 'weixin-java-mp' 替换为目标模块):
cd weixin-java-mp
mvn clean compile --no-transfer-progress
```
### 检查依赖
```bash
# 分析依赖树:
mvn dependency:tree --no-transfer-progress
# 检查依赖更新:
./others/check-dependency-updates.sh
```
### 发布与发布准备
```bash
# 版本检查:
mvn versions:display-property-updates --no-transfer-progress
# 部署(需要凭据):
mvn clean deploy -P release --no-transfer-progress
```
## 重要文件与位置
### 配置文件
- `pom.xml` - 根级 Maven 配置与依赖管理
- `quality-checks/google_checks.xml` - Checkstyle 规则
- `.editorconfig` - IDE 格式化配置
- `.github/workflows/maven-publish.yml` - CI/CD 工作流
### 文档
- `README.md` - 项目概览与使用说明(中文)
- `CONTRIBUTING.md` - 贡献指南
- `demo.md` - 示例项目与演示链接
- 每个模块均有单独的文档与示例
### 测试资源
- `*/src/test/resources/test-config.sample.xml` - 测试配置模板
- 测试运行需要真实的微信 API 凭据
## SDK 使用模式
### Maven 依赖示例
```xml
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId> <!-- 或其他模块 -->
<version>4.7.0</version>
</dependency>
```
### 常见开发区域
- **API 客户端实现**:位于 `*/service/impl/` 目录
- **模型类**:位于 `*/bean/` 目录
- **配置**:位于 `*/config/` 目录
- **工具类**:位于 `weixin-java-common` 的 `*/util/` 目录
## 故障排查
### 构建问题
- **OutOfMemoryError**:增加 Maven 内存:`export MAVEN_OPTS="-Xmx2g"`
- **编译失败**:通常为依赖问题 - 先执行 `mvn clean`
- **Checkstyle 失败**:检查 IDE 的 `.editorconfig` 设置
### 常见陷阱
- **测试默认跳过**:这是正常现象 — 测试需要微信 API 凭据
- **多模块变更**:总是在仓库根目录构建,而不是单独模块
- **分支目标**:Pull Request 必须以 `develop` 分支为目标,而不是 `master` 或 `release`
## 性能说明
- **首次构建**:由于依赖下载,耗时 4-5 分钟
- **增量构建**:通常更快(约 30-60 秒)
- **Checkstyle**:运行迅速(约 50 秒),应当经常运行
- **IDE 性能**:项目使用 Lombok,请确保启用注解处理
注意:本项目为 SDK 库项目,而非可运行应用。修改应以 API 功能为主,不要改动应用级行为。
-4
View File
@@ -1,4 +0,0 @@
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+109
View File
@@ -0,0 +1,109 @@
name: Publish to Maven Central
on:
push:
branches:
- develop
permissions:
contents: write
concurrency:
group: maven-publish-${{ github.ref }}
cancel-in-progress: true
jobs:
build-and-publish:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect and tag release version from commit message
id: version_detect
run: |
COMMIT_MSG=$(git log -1 --pretty=%B)
VERSION=""
TAG=""
IS_RELEASE="false"
if [[ "$COMMIT_MSG" =~ ^:bookmark:\ 发布\ ([0-9]+\.[0-9]+\.[0-9]+)\.B\ 测试版本 ]]; then
BASE_VER="${BASH_REMATCH[1]}"
VERSION="${BASE_VER}.B"
TAG="v${BASE_VER}"
IS_RELEASE="true"
echo "Matched test release commit: VERSION=$VERSION, TAG=$TAG"
# 检查并打tag
if git tag | grep -q "^$TAG$"; then
echo "Tag $TAG already exists."
else
git config user.name "Binary Wang"
git config user.email "a@binarywang.com"
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"
echo "Tag $TAG created and pushed."
fi
elif [[ "$COMMIT_MSG" =~ ^:bookmark:\ 发布\ ([0-9]+\.[0-9]+\.[0-9]+)\ 正式版本 ]]; then
VERSION="${BASH_REMATCH[1]}"
TAG="v${VERSION}"
IS_RELEASE="true"
echo "Matched formal release commit: VERSION=$VERSION, TAG=$TAG"
# 检查并打tag
if git tag | grep -q "^$TAG$"; then
echo "Tag $TAG already exists."
else
git config user.name "Binary Wang"
git config user.email "a@binarywang.com"
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"
echo "Tag $TAG created and pushed."
fi
fi
echo "is_release=$IS_RELEASE" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Set up Java
uses: actions/setup-java@v4
with:
java-version: '8'
distribution: 'temurin'
server-id: central
server-username: MAVEN_USERNAME
server-password: MAVEN_PASSWORD
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
gpg-passphrase: MAVEN_GPG_PASSPHRASE
cache: maven
- name: Verify GPG keys
run: |
echo "Available GPG Keys:"
gpg --list-secret-keys --keyid-format LONG
- name: Generate and set version
id: set_version
run: |
if [[ "${{ steps.version_detect.outputs.is_release }}" == "true" ]]; then
VERSION="${{ steps.version_detect.outputs.version }}"
else
git describe --tags 2>/dev/null || echo "no tag"
TIMESTAMP=$(date +'%Y%m%d.%H%M%S')
GIT_DESCRIBE=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || echo "0.0.1")
VERSION="${GIT_DESCRIBE}-${TIMESTAMP}"
fi
echo "Final version: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
mvn versions:set -DnewVersion=$VERSION --no-transfer-progress
env:
TZ: Asia/Shanghai
- name: Publish to Maven Central
run: |
mvn clean deploy -P release \
-Dmaven.test.skip=true \
-Dgpg.args="--batch --yes --pinentry-mode loopback" \
--no-transfer-progress
env:
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+1 -1
View File
@@ -28,7 +28,7 @@ $ git push
* 定期使用项目仓库内容更新自己仓库内容。
```bash
$ git remote add upstream https://github.com/Wechat-Group/WxJava
$ git remote add upstream https://github.com/binarywang/WxJava
$ git fetch upstream
$ git checkout develop
$ git rebase upstream/develop
+76 -61
View File
@@ -1,72 +1,77 @@
## WxJava - 微信开发 Java SDK
[![Github](https://img.shields.io/github/stars/binarywang/WxJava?logo=github&style=flat&label=Stars)](https://github.com/binarywang/WxJava)
[![Gitee](https://gitee.com/binary/weixin-java-tools/badge/star.svg?theme=blue)](https://gitee.com/binary/weixin-java-tools)
[![GitCode](https://gitcode.com/binary/WxJava/star/badge.svg)](https://gitcode.com/binary/WxJava)
[![码云Gitee](https://gitee.com/binary/weixin-java-tools/badge/star.svg?theme=blue)](https://gitee.com/binary/weixin-java-tools)
[![Github](https://img.shields.io/github/stars/binarywang/WxJava?logo=github&style=flat)](https://github.com/binarywang/WxJava)
[![GitHub release](https://img.shields.io/github/release/binarywang/WxJava.svg)](https://github.com/binarywang/WxJava/releases)
[![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java)
[![Build Status](https://img.shields.io/circleci/project/github/binarywang/WxJava/develop.svg?sanitize=true)](https://circleci.com/gh/binarywang/WxJava/tree/develop)
[![GitHub release](https://img.shields.io/github/release/binarywang/WxJava?label=Release)](https://github.com/binarywang/WxJava/releases)
[![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java?label=Maven)](https://central.sonatype.com/artifact/com.github.binarywang/wx-java/versions)
[![Build Status](https://img.shields.io/circleci/project/github/binarywang/WxJava/develop.svg?sanitize=true&label=Build)](https://circleci.com/gh/binarywang/WxJava/tree/develop)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-支持-blue.svg)](https://www.jetbrains.com/?from=WxJava-weixin-java-tools)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
#### 微信`Java`开发工具包,支持包括微信支付、开放平台、公众号、企业微信、视频号、小程序等微信功能模块的后端开发。
<div align="center">
<a href="https://hellogithub.com/repository/6de6147050c94db4aedfd7098d19f8d8" target="_blank">
<img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=6de6147050c94db4aedfd7098d19f8d8&claim_uid=mwKh0tILBfjlezR" alt="Featured|HelloGitHub" width="250" height="54" />
</a>
<a href="https://trendshift.io/repositories/12152" target="_blank">
<img src="https://trendshift.io/api/badge/repositories/12152" alt="binarywang%2FWxJava | 趋势转变" width="250" height="55" />
</a>
</div>
### 微信`Java`开发工具包,支持包括微信支付、开放平台、公众号、企业微信、视频号、小程序等微信功能模块的后端开发。
<div align="center">
<b>特别赞助</b>
<table cellspacing="0" cellpadding="0" width="500">
<tr>
<td align="center" colspan="3">
<a href="http://www.ccflow.org/?from=wxjava" target="_blank">
<img height="120" src="https://ccfast.cc/AD/ccflow2.png" alt="ccflow">
</a>
</td>
</tr>
<tr>
<td align="center" colspan="2">
<a href="https://www.jeequan.com/product/jeepay.html" target="_blank">
<img height="120" src="https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/wxjava_jeepay.png" alt="计全支付Jeepay,开源支付系统">
</a>
</td>
<td align="center">
<a href="https://www.mall4j.com/cn/?statId=9" target="_blank">
<img height="120" src="https://img.mall4j.com/mall.png" alt="Mall4j">
</a>
</td>
</tr>
<tr>
<td align="center">
<a href="http://mp.weixin.qq.com/mp/homepage?__biz=MzI3MzAwMzk4OA==&hid=1&sn=f31af3bf562b116b061c9ab4edf70b61&scene=18#wechat_redirect" target="_blank">
<img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/develop/images/qrcodes/mp.png" alt="mp qrcode">
</a>
</td>
<td align="center">
<a href="https://www.diboot.com?from=wxjava" target="_blank">
<img height="120" src="https://www.diboot.com/img/diboot_ad.png" alt="diboot低代码开发平台">
</a>
</td>
<td align="center">
<a href="https://www.crmeb.com/xiazai" target="_blank">
<img height="120" src="https://crmebjavamer.oss-cn-beijing.aliyuncs.com/crmebimage/gitee/WechatIMG202.jpg" alt="ad">
</a>
</td>
</tr>
</table>
</div>
<table align="center" cellspacing="0" cellpadding="0" width="500">
<tr>
<td align="center" valign="middle" colspan="3">
<a href="http://www.ccflow.org/?from=wxjava" target="_blank">
<img height="120" src="https://ccfast.cc/AD/ccflow2.png" alt="ccflow">
</a>
</td>
</tr>
<tr>
<td align="center" valign="middle" colspan="3">
<a href="https://www.jeequan.com/product/jeepay.html" target="_blank">
<img height="120" src="https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/wxjava_jeepay.png" alt="计全支付Jeepay,开源支付系统">
</a>
</td>
</tr>
<tr>
<td align="left" valign="middle">
<a href="http://mp.weixin.qq.com/mp/homepage?__biz=MzI3MzAwMzk4OA==&hid=1&sn=f31af3bf562b116b061c9ab4edf70b61&scene=18#wechat_redirect" target="_blank">
<img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/develop/images/qrcodes/mp.png" alt="mp qrcode">
</a>
</td>
<td valign="middle">
<a href="https://www.diboot.com?from=wxjava" target="_blank">
<img height="120" src="https://www.diboot.com/img/diboot_ad.png" alt="diboot低代码开发平台"/>
</a>
</td>
<td align="right" valign="middle">
<a href="https://www.iyque.cn/" target="_blank">
<img height="120" src="https://iyque-1251309172.cos.ap-nanjing.myqcloud.com/advert/wxjava.jpg" alt="aliyun ad">
</a>
</td>
</tr>
<tr>
<td colspan="3" align="center">
<a href="https://hellogithub.com/repository/6de6147050c94db4aedfd7098d19f8d8" target="_blank">
<img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=6de6147050c94db4aedfd7098d19f8d8&claim_uid=mwKh0tILBfjlezR"
alt="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" />
</a>
<a href="https://trendshift.io/repositories/12152" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12152" alt="binarywang%2FWxJava | 趋势转变" style="width: 250px; height: 55px;" width="250" height="55"/>
</a>
</td>
</tr>
</table>
### 重要信息
1. [`WxJava` 荣获 `GitCode` 2024年度十大开源社区奖项](https://mp.weixin.qq.com/s/wM_UlMsDm3IZ1CPPDvcvQw)。
2. 项目合作洽谈请联系微信`binary0000`(在微信里自行搜索并添加好友,请注明来意,如有关于SDK问题需讨论请参考下文入群讨论,不要加此微信)。
3. **2024-12-30 发布 [【4.7.0正式版】](https://mp.weixin.qq.com/s/_7k-XLYBqeJJhvHWCsdT0A)**!
4. 贡献源码可以参考视频:[【贡献源码全过程(上集)】](https://mp.weixin.qq.com/s/3xUZSATWwHR_gZZm207h7Q)、[【贡献源码全过程(下集)】](https://mp.weixin.qq.com/s/nyzJwVVoYSJ4hSbwyvTx9A) ,友情提供:[程序员小山与Bug](https://space.bilibili.com/473631007)
5. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用 `maven` 或 `gradle` 引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;
6. 微信开发新手请务必阅读【开发文档】([Gitee Wiki](https://gitee.com/binary/weixin-java-tools/wikis/Home) 或者 [Github Wiki](https://github.com/binarywang/WxJava/wiki))的常见问题部分,可以少走很多弯路,节省不少时间。
7. 技术交流群:想获得QQ群/微信群/钉钉企业群等信息的同学,请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式,同时也可以在微信中搜索 `weixin-java-tools` 或 `WxJava` 后选择正确的公众号进行关注,该公众号会及时通知SDK相关更新信息,并不定期分享微信Java开发相关技术知识;
8. 钉钉技术交流群:`32206329`(技术交流2群), `30294972`(技术交流1群,目前已满),`35724728`(通知群,实时通知Github项目变更记录)。
9. 微信开发新手或者Java开发新手在群内提问或新开Issue提问前,请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md),并确保已查阅过 [【开发文档Wiki】](https://github.com/binarywang/WxJava/wiki) ,避免浪费大家的宝贵时间;
10. 寻求帮助时需贴代码或大长串异常信息的,请利用 http://paste.ubuntu.com
5. 贡献源码可以参考视频:[【贡献源码全过程(上集)】](https://mp.weixin.qq.com/s/3xUZSATWwHR_gZZm207h7Q)、[【贡献源码全过程(下集)】](https://mp.weixin.qq.com/s/nyzJwVVoYSJ4hSbwyvTx9A) ,友情提供:[程序员小山与Bug](https://space.bilibili.com/473631007)
6. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用 `maven` 或 `gradle` 引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;
7. 微信开发新手请务必阅读【开发文档】([Gitee Wiki](https://gitee.com/binary/weixin-java-tools/wikis/Home) 或者 [Github Wiki](https://github.com/binarywang/WxJava/wiki))的常见问题部分,可以少走很多弯路,节省不少时间。
8. 技术交流群:想获得QQ群/微信群/钉钉企业群等信息的同学,请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式,同时也可以在微信中搜索 `weixin-java-tools` 或 `WxJava` 后选择正确的公众号进行关注,该公众号会及时通知SDK相关更新信息,并不定期分享微信Java开发相关技术知识;
9. 钉钉技术交流群:`32206329`(技术交流2群), `30294972`(技术交流1群,目前已满),`35724728`(通知群,实时通知Github项目变更记录)。
10. 微信开发新手或者Java开发新手在群内提问或新开Issue提问前,请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md),并确保已查阅过 [【开发文档Wiki】](https://github.com/binarywang/WxJava/wiki) ,避免浪费大家的宝贵时间;
11. 寻求帮助时需贴代码或大长串异常信息的,请利用 http://paste.ubuntu.com
--------------------------------
### 其他说明
@@ -84,7 +89,7 @@
---------------------------------
### Maven 引用方式
注意:最新版本(包括测试版)为 [![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java),以下为最新正式版。
注意:最新版本(包括测试版)为 [![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](https://central.sonatype.com/artifact/com.github.binarywang/wx-java/versions),以下为最新正式版。
```xml
<dependency>
@@ -101,6 +106,13 @@
- 企业微信:`weixin-java-cp`
- 微信视频号/微信小店:`weixin-java-channel`
**注意**:
- **移动应用开发**:如果你的移动应用(iOS/Android App)需要接入微信登录、分享等功能:
- 微信登录(网页授权):使用 `weixin-java-open` 模块,在服务端处理 OAuth 授权
- 微信支付:使用 `weixin-java-pay` 模块
- 客户端集成:需使用微信官方提供的移动端SDK(iOS/Android),本项目为服务端SDK
- **微信开放平台**(`weixin-java-open`)主要用于第三方平台,代公众号或小程序进行开发和管理
---------------------------------
### 版本说明
@@ -108,10 +120,13 @@
<details>
<summary>点此展开查看</summary>
1. 本项目定为大约每两个月发布一次正式版(同时 `develop` 分支代码合并进入 `release` 分支),版本号格式为 `X.X.0`(如`2.1.0`,`2.2.0`等),遇到重大问题需修复会及时提交新版本,欢迎大家随时提交Pull Request;
2. BUG修复和新特性一般会先发布成小版本作为临时测试版本(如`3.6.8.B`,即尾号不为0,并添加B,以区别于正式版),代码仅存在于 `develop` 分支中;
3. 目前最新版本号为 [![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java) ,也可以通过访问链接 [【微信支付】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-pay%22) 、[【微信小程序】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-miniapp%22) 、[【公众号】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-mp%22) 、[【企业微信】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-cp%22)、[【开放平台】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-open%22)
分别查看所有最新的版本。
1. 本项目定为大约每半年左右发布一次正式版,遇到重大问题需修复会及时提交新版本,欢迎大家随时提交 `Pull Request`;
2. 每次代码更新都会自动构建出新版本方便及时尝鲜,版本号格式为 `x.x.x-时间戳`;
3. 发布正式版时,`develop` 分支代码合并进入 `release` 分支),版本号格式为 `X.X.0`(如`2.1.0`,`2.2.0`等);
4. 每隔一段时间后,会发布测试版本(如`3.6.8.B`,即尾号不为0,并添加B,以区别于正式版),代码仅存在于 `develop` 分支中;
5. 目前最新版本号为 [![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java) ,也可以通过访问以下链接分别查看各个模块最新的版本:
[【微信支付】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-pay/versions) 、[【小程序】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-miniapp/versions) 、[【公众号】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-mp/versions) 、[【企业微信】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-cp/versions)、[【开放平台】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-open/versions)、[【视频号】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-channel/versions)
</details>
+80
View File
@@ -0,0 +1,80 @@
# WeChat Mini Program Customer Service Management
This document describes the new customer service management functionality added to the WxJava Mini Program SDK.
## Overview
Previously, the mini program module only had:
- `WxMaCustomserviceWorkService` - For binding mini programs to enterprise WeChat customer service
- `WxMaMsgService.sendKefuMsg()` - For sending customer service messages
The new `WxMaKefuService` adds comprehensive customer service management capabilities:
## Features
### Customer Service Account Management
- `kfList()` - Get list of customer service accounts
- `kfAccountAdd()` - Add new customer service account
- `kfAccountUpdate()` - Update customer service account
- `kfAccountDel()` - Delete customer service account
### Session Management
- `kfSessionCreate()` - Create customer service session
- `kfSessionClose()` - Close customer service session
- `kfSessionGet()` - Get customer session status
- `kfSessionList()` - Get customer service session list
## Usage Example
```java
// Get the customer service management service
WxMaKefuService kefuService = wxMaService.getKefuService();
// Add a new customer service account
WxMaKfAccountRequest request = WxMaKfAccountRequest.builder()
.kfAccount("service001@example")
.kfNick("Customer Service 001")
.kfPwd("password123")
.build();
boolean result = kefuService.kfAccountAdd(request);
// Create a session between user and customer service
boolean sessionResult = kefuService.kfSessionCreate("user_openid", "service001@example");
// Get customer service list
WxMaKfList kfList = kefuService.kfList();
```
## Bean Classes
### Request Objects
- `WxMaKfAccountRequest` - For customer service account operations
- `WxMaKfSessionRequest` - For session operations
### Response Objects
- `WxMaKfInfo` - Customer service account information
- `WxMaKfList` - List of customer service accounts
- `WxMaKfSession` - Session information
- `WxMaKfSessionList` - List of sessions
## API Endpoints
The service uses the following WeChat Mini Program API endpoints:
- `https://api.weixin.qq.com/cgi-bin/customservice/getkflist` - Get customer service list
- `https://api.weixin.qq.com/customservice/kfaccount/add` - Add customer service account
- `https://api.weixin.qq.com/customservice/kfaccount/update` - Update customer service account
- `https://api.weixin.qq.com/customservice/kfaccount/del` - Delete customer service account
- `https://api.weixin.qq.com/customservice/kfsession/create` - Create session
- `https://api.weixin.qq.com/customservice/kfsession/close` - Close session
- `https://api.weixin.qq.com/customservice/kfsession/getsession` - Get session
- `https://api.weixin.qq.com/customservice/kfsession/getsessionlist` - Get session list
## Integration
The service is automatically available through the main `WxMaService` interface:
```java
WxMaKefuService kefuService = wxMaService.getKefuService();
```
This fills the gap mentioned in the original issue and provides full customer service management capabilities for WeChat Mini Programs.
+154
View File
@@ -0,0 +1,154 @@
# 微信支付新版商户转账API支持
## 问题解答
**问题**: 新开通的商户号只能使用最新版本的商户转账接口,WxJava是否支持?
**答案**: **WxJava 已经完整支持新版商户转账API!** 从2025年1月15日开始生效的新版转账API已在WxJava中实现。
## 新版转账API特性
### 1. API接口对比
| 特性 | 传统转账API | 新版转账API (2025.1.15+) |
|------|-------------|-------------------------|
| **服务类** | `MerchantTransferService` | `TransferService` |
| **API路径** | `/v3/transfer/batches` | `/v3/fund-app/mch-transfer/transfer-bills` |
| **转账方式** | 批量转账 | 单笔转账 |
| **场景支持** | 基础场景 | 丰富场景(如佣金报酬等) |
| **撤销功能** | ❌ 不支持 | ✅ 支持 |
| **授权模式** | 仅需确认模式 | ✅ 支持免确认授权模式 |
| **适用范围** | 所有商户 | **新开通商户必须使用** |
### 2. 新版API功能列表
✅ **发起转账** - `transferBills()`
✅ **查询转账** - `getBillsByOutBillNo()` / `getBillsByTransferBillNo()`
✅ **撤销转账** - `transformBillsCancel()`
✅ **回调通知** - `parseTransferBillsNotifyResult()`
✅ **RSA加密** - 自动处理用户姓名加密
✅ **场景支持** - 支持多种转账场景ID
✅ **授权模式** - 支持免确认收款授权模式
### 3. 收款授权模式支持
**新增功能:免确认收款授权模式**
- **需确认收款授权模式**(默认):用户需要手动确认才能收款
- **免确认收款授权模式**:用户授权后,收款无需确认,转账直接到账
#### 使用方法
```java
// 免确认授权模式 - 提升用户体验
TransferBillsRequest request = TransferBillsRequest.newBuilder()
.receiptAuthorizationMode(WxPayConstants.ReceiptAuthorizationMode.NO_CONFIRM_RECEIPT_AUTHORIZATION)
// 其他参数...
.build();
// 需确认授权模式(默认)
TransferBillsRequest request2 = TransferBillsRequest.newBuilder()
.receiptAuthorizationMode(WxPayConstants.ReceiptAuthorizationMode.CONFIRM_RECEIPT_AUTHORIZATION)
// 其他参数...
.build();
```
## 快速开始
### 1. 获取服务实例
```java
// 获取WxPayService实例
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(config);
// 获取新版转账服务 - 这就是新开通商户需要使用的服务!
TransferService transferService = wxPayService.getTransferService();
```
### 2. 发起转账(新版API)
```java
// 构建转账请求
TransferBillsRequest request = TransferBillsRequest.newBuilder()
.appid("your_appid") // 应用ID
.outBillNo("T" + System.currentTimeMillis()) // 商户转账单号
.transferSceneId("1005") // 转账场景ID(佣金报酬)
.openid("user_openid") // 用户openid
.userName("张三") // 收款用户姓名(可选,自动加密)
.transferAmount(100) // 转账金额(分)
.transferRemark("佣金报酬") // 转账备注
.build();
// 发起转账
TransferBillsResult result = transferService.transferBills(request);
System.out.println("转账成功,微信转账单号:" + result.getTransferBillNo());
```
### 3. 查询转账结果
```java
// 通过商户单号查询
TransferBillsGetResult result = transferService.getBillsByOutBillNo("T1642567890123");
// 通过微信转账单号查询
TransferBillsGetResult result2 = transferService.getBillsByTransferBillNo("wx_transfer_bill_no");
System.out.println("转账状态:" + result.getState());
```
### 4. 撤销转账(新功能)
```java
// 撤销转账
TransferBillsCancelResult cancelResult = transferService.transformBillsCancel("T1642567890123");
System.out.println("撤销状态:" + cancelResult.getState());
```
## 重要说明
### 转账场景ID (transfer_scene_id)
- **1005**: 佣金报酬(常用场景)
- 其他场景需要在微信商户平台申请
### 转账状态说明
- **ACCEPTED**: 转账已受理
- **PROCESSING**: 转账处理中
- **SUCCESS**: 转账成功
- **FAIL**: 转账失败
- **CANCELLED**: 转账撤销完成
### 新开通商户使用建议
1. **优先使用** `TransferService` (新版API)
2. **不要使用** `MerchantTransferService` (可能不支持)
3. **必须设置** 转账场景ID (`transfer_scene_id`)
4. **建议开启** 回调通知以实时获取转账结果
## 完整示例代码
详细的使用示例请参考:
- 📄 [NEW_TRANSFER_API_USAGE.md](./NEW_TRANSFER_API_USAGE.md) - 详细使用指南
- 💻 [NewTransferApiExample.java](./weixin-java-pay/src/main/java/com/github/binarywang/wxpay/example/NewTransferApiExample.java) - 完整代码示例
## 常见问题
**Q: 我是新开通的商户,应该使用哪个服务?**
A: 使用 `TransferService`,这是专为新版API设计的服务。
**Q: 新版API和旧版API有什么区别?**
A: 新版API使用单笔转账模式,支持更丰富的转账场景,并且支持撤销功能。
**Q: 如何设置转账场景ID?**
A: 在商户平台申请相应场景,常用的佣金报酬场景ID是"1005"。
**Q: 用户姓名需要加密吗?**
A: WxJava会自动处理RSA加密,您只需要传入明文姓名即可。
## 版本要求
- WxJava 版本:4.7.0+
- 支持时间:2025年1月15日+
- 适用商户:所有商户(新开通商户强制使用)
通过以上说明,新开通的微信支付商户可以放心使用WxJava进行商户转账操作!
+242
View File
@@ -0,0 +1,242 @@
# 微信支付新版商户转账API使用指南
## 概述
从2025年1月15日开始,微信支付推出了新版的商户转账API。新开通的商户号只能使用最新版本的商户转账接口。WxJava 已经完整支持新版转账API。
## API对比
### 传统转账API (仍然支持)
- **服务类**: `MerchantTransferService`
- **API前缀**: `/v3/transfer/batches`
- **特点**: 支持批量转账,一次可以转账给多个用户
### 新版转账API (2025.1.15+)
- **服务类**: `TransferService`
- **API前缀**: `/v3/fund-app/mch-transfer/transfer-bills`
- **特点**: 单笔转账,支持更丰富的转账场景
## 收款授权模式功能
### 授权模式说明
微信支付转账支持两种收款授权模式:
#### 1. 需确认收款授权模式(默认)
- **常量**: `WxPayConstants.ReceiptAuthorizationMode.CONFIRM_RECEIPT_AUTHORIZATION`
- **特点**: 用户收到转账后需要手动点击确认才能到账
- **适用场景**: 一般的转账场景
- **用户体验**: 安全性高,但需要额外操作
#### 2. 免确认收款授权模式
- **常量**: `WxPayConstants.ReceiptAuthorizationMode.NO_CONFIRM_RECEIPT_AUTHORIZATION`
- **特点**: 用户事先授权后,转账直接到账,无需确认
- **适用场景**: 高频转账场景,如佣金发放、返现等
- **用户体验**: 体验流畅,无需额外操作
- **前提条件**: 需要用户事先进行授权
### 使用示例
#### 免确认授权模式转账
```java
TransferBillsRequest request = TransferBillsRequest.newBuilder()
.appid("your_appid")
.outBillNo("NO_CONFIRM_" + System.currentTimeMillis())
.transferSceneId("1005") // 佣金报酬场景
.openid("user_openid")
.transferAmount(200) // 2元
.transferRemark("免确认收款转账")
.receiptAuthorizationMode(WxPayConstants.ReceiptAuthorizationMode.NO_CONFIRM_RECEIPT_AUTHORIZATION)
.userRecvPerception("Y")
.build();
try {
TransferBillsResult result = transferService.transferBills(request);
System.out.println("转账成功,直接到账:" + result.getTransferBillNo());
} catch (WxPayException e) {
if ("USER_NOT_AUTHORIZED".equals(e.getErrCode())) {
System.err.println("用户未授权免确认收款,请先引导用户进行授权");
}
}
```
#### 需确认授权模式转账(默认)
```java
TransferBillsRequest request = TransferBillsRequest.newBuilder()
.appid("your_appid")
.outBillNo("CONFIRM_" + System.currentTimeMillis())
.transferSceneId("1005")
.openid("user_openid")
.transferAmount(150) // 1.5元
.transferRemark("需确认收款转账")
// .receiptAuthorizationMode(...) // 不设置时使用默认的确认模式
.userRecvPerception("Y")
.build();
TransferBillsResult result = transferService.transferBills(request);
System.out.println("转账发起成功,等待用户确认:" + result.getPackageInfo());
```
### 错误处理
使用免确认授权模式时,需要处理以下可能的错误:
```java
try {
TransferBillsResult result = transferService.transferBills(request);
} catch (WxPayException e) {
switch (e.getErrCode()) {
case "USER_NOT_AUTHORIZED":
// 用户未授权免确认收款
System.err.println("请先引导用户进行免确认收款授权");
// 可以引导用户到授权页面
break;
case "AUTHORIZATION_EXPIRED":
// 授权已过期
System.err.println("用户授权已过期,请重新授权");
break;
default:
System.err.println("转账失败:" + e.getMessage());
}
}
```
### 使用建议
1. **高频转账场景**推荐使用免确认模式,提升用户体验
2. **首次使用**需引导用户进行授权
3. **处理异常**妥善处理授权相关异常,提供友好的错误提示
4. **场景选择**根据业务场景选择合适的授权模式
## 使用新版转账API
### 1. 获取服务实例
```java
// 获取WxPayService实例
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(config);
// 获取新版转账服务
TransferService transferService = wxPayService.getTransferService();
```
### 2. 发起转账
```java
// 构建转账请求
TransferBillsRequest request = TransferBillsRequest.newBuilder()
.appid("your_appid") // 应用ID
.outBillNo("T" + System.currentTimeMillis()) // 商户转账单号
.transferSceneId("1005") // 转账场景ID(佣金报酬)
.openid("user_openid") // 用户openid
.userName("张三") // 收款用户姓名(可选,需要加密)
.transferAmount(100) // 转账金额(分)
.transferRemark("佣金报酬") // 转账备注
.notifyUrl("https://your-domain.com/notify") // 回调地址(可选)
.userRecvPerception("Y") // 用户收款感知(可选)
.build();
try {
TransferBillsResult result = transferService.transferBills(request);
System.out.println("转账成功,微信转账单号:" + result.getTransferBillNo());
System.out.println("状态:" + result.getState());
} catch (WxPayException e) {
System.err.println("转账失败:" + e.getMessage());
}
```
### 3. 查询转账结果
```java
// 通过商户单号查询
String outBillNo = "T1642567890123";
TransferBillsGetResult result = transferService.getBillsByOutBillNo(outBillNo);
// 通过微信转账单号查询
String transferBillNo = "1000000000000000000000000001";
TransferBillsGetResult result2 = transferService.getBillsByTransferBillNo(transferBillNo);
System.out.println("转账状态:" + result.getState());
System.out.println("转账金额:" + result.getTransferAmount());
```
### 4. 撤销转账
```java
// 撤销转账(仅在特定状态下可撤销)
String outBillNo = "T1642567890123";
TransferBillsCancelResult cancelResult = transferService.transformBillsCancel(outBillNo);
System.out.println("撤销结果:" + cancelResult.getState());
```
### 5. 处理回调通知
```java
// 在回调接口中处理通知
@PostMapping("/transfer/notify")
public String handleTransferNotify(HttpServletRequest request) throws Exception {
String notifyData = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
// 构建签名头
SignatureHeader header = new SignatureHeader();
header.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
header.setNonce(request.getHeader("Wechatpay-Nonce"));
header.setSignature(request.getHeader("Wechatpay-Signature"));
header.setSerial(request.getHeader("Wechatpay-Serial"));
try {
TransferBillsNotifyResult notifyResult = transferService.parseTransferBillsNotifyResult(notifyData, header);
// 处理业务逻辑
String outBillNo = notifyResult.getOutBillNo();
String state = notifyResult.getState();
System.out.println("转账单号:" + outBillNo + ",状态:" + state);
return "SUCCESS";
} catch (WxPayException e) {
System.err.println("验签失败:" + e.getMessage());
return "FAIL";
}
}
```
## 重要参数说明
### 转账场景ID (transfer_scene_id)
- **1005**: 佣金报酬(常用)
- 其他场景ID需要在商户平台申请
### 转账状态
- **PROCESSING**: 转账中
- **SUCCESS**: 转账成功
- **FAILED**: 转账失败
- **REFUNDED**: 已退款
### 用户收款感知 (user_recv_perception)
- **Y**: 用户会收到微信转账通知
- **N**: 用户不会收到微信转账通知
## 新旧API对比总结
| 特性 | 传统API (MerchantTransferService) | 新版API (TransferService) |
|------|----------------------------------|---------------------------|
| 发起方式 | 批量转账 | 单笔转账 |
| API路径 | `/v3/transfer/batches` | `/v3/fund-app/mch-transfer/transfer-bills` |
| 场景支持 | 基础转账场景 | 丰富的转账场景 |
| 回调通知 | 支持 | 支持 |
| 撤销功能 | 不支持 | 支持 |
| 适用商户 | 所有商户 | 新开通商户必须使用 |
## 注意事项
1. **新开通的商户号**: 必须使用新版API (`TransferService`)
2. **转账场景ID**: 需要在商户平台申请相应的转账场景
3. **用户姓名加密**: 如果传入用户姓名,会自动进行RSA加密
4. **回调验签**: 建议开启回调验签以确保安全性
5. **错误处理**: 妥善处理各种异常情况
通过以上指南,您可以轻松使用WxJava的新版商户转账API功能。
+112
View File
@@ -0,0 +1,112 @@
# WxJava Quarkus/GraalVM Native Image Support
## 概述
从 4.7.8.B 版本开始,WxJava 提供了对 Quarkus 和 GraalVM Native Image 的支持。这允许您将使用 WxJava 的应用程序编译为原生可执行文件,从而获得更快的启动速度和更低的内存占用。
## 问题背景
在之前的版本中,使用 Quarkus 构建 Native Image 时会遇到以下错误:
```
Error: Unsupported features in 3 methods
Detailed message:
Error: Detected an instance of Random/SplittableRandom class in the image heap.
Instances created during image generation have cached seed values and don't behave as expected.
The culprit object has been instantiated by the 'org.apache.http.impl.auth.NTLMEngineImpl' class initializer
```
## 解决方案
为了解决这个问题,WxJava 进行了以下改进:
### 1. Random 实例的延迟初始化
所有 `java.util.Random` 实例都已改为延迟初始化,避免在类加载时创建:
- `RandomUtils` - 使用双重检查锁定模式延迟初始化
- `SignUtils` - 使用双重检查锁定模式延迟初始化
- `WxCryptUtil` - 使用双重检查锁定模式延迟初始化
### 2. Native Image 配置
在 `weixin-java-common` 模块中添加了 GraalVM Native Image 配置文件:
- `META-INF/native-image/com.github.binarywang/weixin-java-common/native-image.properties`
- 配置 Apache HttpClient 相关类在运行时初始化,避免在构建时创建 SecureRandom 实例
- `META-INF/native-image/com.github.binarywang/weixin-java-common/reflect-config.json`
- 配置反射访问的类和方法
## 使用方式
### Quarkus 项目配置
在您的 Quarkus 项目中使用 WxJava,只需正常引入依赖即可:
```xml
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId> <!-- 或其他模块 -->
<version>4.7.8.B</version>
</dependency>
```
### 构建 Native Image
使用 Quarkus 构建原生可执行文件:
```bash
./mvnw package -Pnative
```
或使用容器构建:
```bash
./mvnw package -Pnative -Dquarkus.native.container-build=true
```
### GraalVM Native Image
如果直接使用 GraalVM Native Image 工具:
```bash
native-image --no-fallback \
-H:+ReportExceptionStackTraces \
-jar your-application.jar
```
WxJava 的配置文件会自动被 Native Image 工具识别和应用。
## 测试验证
建议在构建 Native Image 后进行以下测试:
1. 验证应用程序可以正常启动
2. 验证微信 API 调用功能正常
3. 验证随机字符串生成功能正常
4. 验证加密/解密功能正常
## 已知限制
- 本配置主要针对 Quarkus 3.x 和 GraalVM 22.x+ 版本进行测试
- 如果使用其他 Native Image 构建工具(如 Spring Native),可能需要额外配置
- 部分反射使用可能需要根据实际使用的 WxJava 功能进行调整
## 问题反馈
如果在使用 Quarkus/GraalVM Native Image 时遇到问题,请通过以下方式反馈:
1. 在 [GitHub Issues](https://github.com/binarywang/WxJava/issues) 提交问题
2. 提供详细的错误信息和 Native Image 构建日志
3. 说明使用的 Quarkus 版本和 GraalVM 版本
## 参考资料
- [Quarkus 官方文档](https://quarkus.io/)
- [GraalVM Native Image 文档](https://www.graalvm.org/latest/reference-manual/native-image/)
- [Quarkus Tips for Writing Native Applications](https://quarkus.io/guides/writing-native-applications-tips)
## 贡献
欢迎提交 PR 完善 Quarkus/GraalVM 支持!如果您发现了新的兼容性问题或有改进建议,请参考 [代码贡献指南](CONTRIBUTING.md)。
Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Vendored Regular → Executable
View File
+39 -29
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.1.B</version>
<version>4.8.0</version>
<packaging>pom</packaging>
<name>WxJava - Weixin/Wechat Java SDK</name>
<description>微信开发Java SDK</description>
@@ -136,10 +136,8 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<httpclient.version>4.5.13</httpclient.version>
<jetty.version>9.4.56.v20240826</jetty.version>
<!-- 这个不能用10以上的版本,不支持jdk8-->
<jetty.version>9.4.57.v20241219</jetty.version> <!-- 这个不能用10以上的版本,不支持jdk8-->
</properties>
<dependencyManagement>
<dependencies>
<dependency>
@@ -156,7 +154,13 @@
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.5.0</version>
<version>4.12.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.5</version>
<scope>provided</scope>
</dependency>
@@ -183,7 +187,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
<version>3.18.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
@@ -198,17 +202,19 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
<version>33.3.1-jre</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.15.2</version>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>2.18.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 测试所用依赖 -->
@@ -327,22 +333,11 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.78.1</version>
<version>1.80</version>
</dependency>
</dependencies>
</dependencyManagement>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<profiles>
<profile>
<id>doclint-java8-disable</id>
@@ -432,14 +427,14 @@
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.3</version>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.7.0</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
<deploymentName>Release WxJava:${project.version}</deploymentName>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
</configuration>
</plugin>
<plugin>
@@ -473,6 +468,21 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version> <!-- 建议使用最新版本 -->
<executions>
<execution>
<id>attach-sources</id>
<!-- 绑定到 verify 阶段,在 install 之前执行 -->
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal> <!-- 使用 jar-no-fork 效率更高 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
+2 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<packaging>pom</packaging>
<artifactId>wx-java-solon-plugins</artifactId>
@@ -14,7 +14,7 @@
<description>WxJava 各个模块的 Solon Plugin</description>
<properties>
<solon.version>3.0.1</solon.version>
<solon.version>3.2.0</solon.version>
</properties>
<modules>
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -8,6 +8,7 @@ import com.binarywang.solon.wxjava.channel.service.WxChannelMultiServicesImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.WxChannelService;
import me.chanjar.weixin.channel.api.impl.WxChannelServiceHttpComponentsImpl;
import me.chanjar.weixin.channel.api.impl.WxChannelServiceHttpClientImpl;
import me.chanjar.weixin.channel.api.impl.WxChannelServiceImpl;
import me.chanjar.weixin.channel.config.WxChannelConfig;
@@ -84,6 +85,9 @@ public abstract class AbstractWxChannelConfiguration {
case HTTP_CLIENT:
wxChannelService = new WxChannelServiceHttpClientImpl();
break;
case HTTP_COMPONENTS:
wxChannelService = new WxChannelServiceHttpComponentsImpl();
break;
default:
wxChannelService = new WxChannelServiceImpl();
break;
@@ -11,6 +11,10 @@ public enum HttpClientType {
* HttpClient
*/
HTTP_CLIENT,
/**
* HttpComponents
*/
HTTP_COMPONENTS
// WxChannelServiceOkHttpImpl 实现经测试无法正常完成业务固暂不支持OK_HTTP方式
// /**
// * OkHttp.
@@ -0,0 +1,92 @@
# wx-java-channel-solon-plugin
## 快速开始
1. 引入依赖
```xml
<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-channel-solon-plugin</artifactId>
<version>${version}</version>
</dependency>
<!-- 配置存储方式为jedis 则引入jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<!-- 配置存储方式为redisson 则引入redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
</dependencies>
```
2. 添加配置(app.properties)
```properties
# 视频号配置(必填)
## 视频号小店的appId和secret
wx.channel.app-id=@appId
wx.channel.secret=@secret
# 视频号配置 选填
## 设置视频号小店消息服务器配置的token
wx.channel.token=@token
## 设置视频号小店消息服务器配置的EncodingAESKey
wx.channel.aes-key=
## 支持JSON或者XML格式,默认JSON
wx.channel.msg-data-format=JSON
## 是否使用稳定版 Access Token
wx.channel.use-stable-access-token=false
# ConfigStorage 配置(选填)
## 配置类型: memory(默认), jedis, redisson, redis_template
wx.channel.config-storage.type=memory
## 相关redis前缀配置: wx:channel(默认)
wx.channel.config-storage.key-prefix=wx:channel
wx.channel.config-storage.redis.host=127.0.0.1
wx.channel.config-storage.redis.port=6379
wx.channel.config-storage.redis.password=123456
# http 客户端配置(选填)
## # http客户端类型: http_client(默认)
wx.channel.config-storage.http-client-type=http_client
wx.channel.config-storage.http-proxy-host=
wx.channel.config-storage.http-proxy-port=
wx.channel.config-storage.http-proxy-username=
wx.channel.config-storage.http-proxy-password=
## 最大重试次数,默认:5 次,如果小于 0,则为 0
wx.channel.config-storage.max-retry-times=5
## 重试时间间隔步进,默认:1000 毫秒,如果小于 0,则为 1000
wx.channel.config-storage.retry-sleep-millis=1000
```
3. 自动注入的类型
- `WxChannelService`
- `WxChannelConfig`
4. 使用样例
```java
import me.chanjar.weixin.channel.api.WxChannelService;
import me.chanjar.weixin.channel.bean.shop.ShopInfoResponse;
import me.chanjar.weixin.channel.util.JsonUtils;
import me.chanjar.weixin.common.error.WxErrorException;
import org.noear.solon.annotation.Inject;
@Component
public class DemoService {
@Inject
private WxChannelService wxChannelService;
public String getShopInfo() throws WxErrorException {
// 获取店铺基本信息
ShopInfoResponse response = wxChannelService.getBasicService().getShopInfo();
// 此处为演示,如果要返回response的结果,建议自己封装一个VO,避免直接返回response
return JsonUtils.encode(response);
}
}
```
@@ -3,7 +3,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -7,10 +7,7 @@ import com.binarywang.solon.wxjava.cp_multi.service.WxCpMultiServicesImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.impl.WxCpServiceApacheHttpClientImpl;
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
import me.chanjar.weixin.cp.api.impl.WxCpServiceJoddHttpImpl;
import me.chanjar.weixin.cp.api.impl.WxCpServiceOkHttpImpl;
import me.chanjar.weixin.cp.api.impl.*;
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import org.apache.commons.lang3.StringUtils;
@@ -96,6 +93,9 @@ public abstract class AbstractWxCpConfiguration {
case HTTP_CLIENT:
wxCpService = new WxCpServiceApacheHttpClientImpl();
break;
case HTTP_COMPONENTS:
wxCpService = new WxCpServiceHttpComponentsImpl();
break;
default:
wxCpService = new WxCpServiceImpl();
break;
@@ -117,6 +117,10 @@ public class WxCpMultiProperties implements Serializable {
* HttpClient
*/
HTTP_CLIENT,
/**
* HttpComponents
*/
HTTP_COMPONENTS,
/**
* OkHttp
*/
@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -46,13 +46,20 @@ public class WxPayAutoConfiguration {
payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
payConfig.setUseSandboxEnv(this.properties.isUseSandboxEnv());
payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));
//以下是apiv3以及支付分相关
payConfig.setServiceId(StringUtils.trimToNull(this.properties.getServiceId()));
payConfig.setPayScoreNotifyUrl(StringUtils.trimToNull(this.properties.getPayScoreNotifyUrl()));
payConfig.setPayScorePermissionNotifyUrl(StringUtils.trimToNull(this.properties.getPayScorePermissionNotifyUrl()));
payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath()));
payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));
payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getCertSerialNo()));
payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiv3Key()));
payConfig.setPublicKeyId(StringUtils.trimToNull(this.properties.getPublicKeyId()));
payConfig.setPublicKeyPath(StringUtils.trimToNull(this.properties.getPublicKeyPath()));
payConfig.setApiHostUrl(StringUtils.trimToNull(this.properties.getApiHostUrl()));
payConfig.setStrictlyNeedWechatPaySerial(this.properties.isStrictlyNeedWechatPaySerial());
payConfig.setFullPublicKeyModel(this.properties.isFullPublicKeyModel());
wxPayService.setConfig(payConfig);
return wxPayService;
@@ -82,4 +82,40 @@ public class WxPayProperties {
*/
private boolean useSandboxEnv;
/**
* 微信支付异步回调地址,通知url必须为直接可访问的url,不能携带参数
*/
private String notifyUrl;
/**
* 微信支付分授权回调地址
*/
private String payScorePermissionNotifyUrl;
/**
* 公钥ID
*/
private String publicKeyId;
/**
* pub_key.pem证书文件的绝对路径或者以classpath:开头的类路径.
*/
private String publicKeyPath;
/**
* 自定义API主机地址,用于替换默认的 https://api.mch.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String apiHostUrl;
/**
* 是否将全部v3接口的请求都添加Wechatpay-Serial请求头,默认不添加
*/
private boolean strictlyNeedWechatPaySerial = false;
/**
* 是否完全使用公钥模式(用以微信从平台证书到公钥的灰度切换),默认不使用
*/
private boolean fullPublicKeyModel = false;
}
@@ -3,7 +3,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -18,11 +18,13 @@ import org.noear.solon.annotation.Condition;
import org.noear.solon.annotation.Configuration;
import org.noear.solon.annotation.Inject;
import org.noear.solon.core.AppContext;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.util.Pool;
import java.time.Duration;
import java.util.Set;
/**
@@ -75,7 +77,7 @@ public class WxQidianStorageAutoConfiguration {
}
private WxQidianConfigStorage jedisConfigStorage() {
Pool jedisPool;
Pool<Jedis> jedisPool;
if (StringUtils.isNotEmpty(redisHost) || StringUtils.isNotEmpty(redisHost2)) {
jedisPool = getJedisPool();
} else {
@@ -104,7 +106,7 @@ public class WxQidianStorageAutoConfiguration {
}
}
private Pool getJedisPool() {
private Pool<Jedis> getJedisPool() {
WxQidianProperties.ConfigStorage storage = wxQidianProperties.getConfigStorage();
RedisProperties redis = storage.getRedis();
@@ -116,7 +118,7 @@ public class WxQidianStorageAutoConfiguration {
config.setMaxIdle(redis.getMaxIdle());
}
if (redis.getMaxWaitMillis() != null) {
config.setMaxWaitMillis(redis.getMaxWaitMillis());
config.setMaxWait(Duration.ofMillis(redis.getMaxWaitMillis()));
}
if (redis.getMinIdle() != null) {
config.setMinIdle(redis.getMinIdle());
+2 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<packaging>pom</packaging>
<artifactId>wx-java-spring-boot-starters</artifactId>
@@ -26,6 +26,7 @@
<module>wx-java-open-spring-boot-starter</module>
<module>wx-java-qidian-spring-boot-starter</module>
<module>wx-java-cp-multi-spring-boot-starter</module>
<module>wx-java-cp-tp-multi-spring-boot-starter</module>
<module>wx-java-cp-spring-boot-starter</module>
<module>wx-java-channel-spring-boot-starter</module>
<module>wx-java-channel-multi-spring-boot-starter</module>
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -119,6 +119,8 @@ public abstract class AbstractWxChannelConfiguration {
config.setAesKey(aesKey);
}
config.setStableAccessToken(useStableAccessToken);
config.setApiHostUrl(StringUtils.trimToNull(wxChannelSingleProperties.getApiHostUrl()));
config.setAccessTokenUrl(StringUtils.trimToNull(wxChannelSingleProperties.getAccessTokenUrl()));
}
private void configHttp(WxChannelDefaultConfigImpl config, WxChannelMultiProperties.ConfigStorage storage) {
@@ -40,4 +40,16 @@ public class WxChannelSingleProperties implements Serializable {
* 是否使用稳定版 Access Token
*/
private boolean useStableAccessToken = false;
/**
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String apiHostUrl;
/**
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
* 例如:http://proxy.company.com:8080/oauth/token
*/
private String accessTokenUrl;
}
@@ -6,7 +6,7 @@
<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-channel-multi-spring-boot-starter</artifactId>
<artifactId>wx-java-channel-spring-boot-starter</artifactId>
<version>${version}</version>
</dependency>
@@ -3,7 +3,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -16,6 +16,8 @@ public abstract class AbstractWxChannelConfigStorageConfiguration {
config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
config.setStableAccessToken(properties.isUseStableAccessToken());
config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
WxChannelProperties.ConfigStorage configStorageProperties = properties.getConfigStorage();
config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
@@ -46,6 +46,18 @@ public class WxChannelProperties {
*/
private boolean useStableAccessToken = false;
/**
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String apiHostUrl;
/**
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
* 例如:http://proxy.company.com:8080/oauth/token
*/
private String accessTokenUrl;
/**
* 存储策略
*/
@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -139,6 +139,9 @@ public abstract class AbstractWxCpConfiguration {
if (StringUtils.isNotBlank(msgAuditLibPath)) {
config.setMsgAuditLibPath(msgAuditLibPath);
}
if (StringUtils.isNotBlank(wxCpSingleProperties.getBaseApiUrl())) {
config.setBaseApiUrl(wxCpSingleProperties.getBaseApiUrl());
}
}
private void configHttp(WxCpDefaultConfigImpl config, WxCpMultiProperties.ConfigStorage storage) {
@@ -43,4 +43,10 @@ public class WxCpSingleProperties implements Serializable {
* 微信企业号应用 会话存档类库路径
*/
private String msgAuditLibPath;
/**
* 自定义企业微信服务器baseUrl,用于替换默认的 https://qyapi.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String baseApiUrl;
}
@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -48,6 +48,12 @@ public class WxCpProperties {
*/
private String msgAuditLibPath;
/**
* 自定义企业微信服务器baseUrl,用于替换默认的 https://qyapi.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String baseApiUrl;
/**
* 配置存储策略,默认内存
*/
@@ -37,6 +37,9 @@ public abstract class AbstractWxCpConfigStorageConfiguration {
if (StringUtils.isNotBlank(msgAuditLibPath)) {
config.setMsgAuditLibPath(msgAuditLibPath);
}
if (StringUtils.isNotBlank(properties.getBaseApiUrl())) {
config.setBaseApiUrl(properties.getBaseApiUrl());
}
WxCpProperties.ConfigStorage storage = properties.getConfigStorage();
String httpProxyHost = storage.getHttpProxyHost();
@@ -0,0 +1,97 @@
# wx-java-cp-multi-spring-boot-starter
企业微信多账号配置
- 实现多 WxCpService 初始化。
- 未实现 WxCpTpService 初始化,需要的小伙伴可以参考多 WxCpService 配置的实现。
- 未实现 WxCpCgService 初始化,需要的小伙伴可以参考多 WxCpService 配置的实现。
## 快速开始
1. 引入依赖
```xml
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java-cp-multi-spring-boot-starter</artifactId>
<version>${version}</version>
</dependency>
```
2. 添加配置(application.properties)
```properties
# 应用 1 配置
wx.cp.corps.tenantId1.corp-id = @corp-id
wx.cp.corps.tenantId1.corp-secret = @corp-secret
## 选填
wx.cp.corps.tenantId1.agent-id = @agent-id
wx.cp.corps.tenantId1.token = @token
wx.cp.corps.tenantId1.aes-key = @aes-key
wx.cp.corps.tenantId1.msg-audit-priKey = @msg-audit-priKey
wx.cp.corps.tenantId1.msg-audit-lib-path = @msg-audit-lib-path
# 应用 2 配置
wx.cp.corps.tenantId2.corp-id = @corp-id
wx.cp.corps.tenantId2.corp-secret = @corp-secret
## 选填
wx.cp.corps.tenantId2.agent-id = @agent-id
wx.cp.corps.tenantId2.token = @token
wx.cp.corps.tenantId2.aes-key = @aes-key
wx.cp.corps.tenantId2.msg-audit-priKey = @msg-audit-priKey
wx.cp.corps.tenantId2.msg-audit-lib-path = @msg-audit-lib-path
# 公共配置
## ConfigStorage 配置(选填)
wx.cp.config-storage.type=memory # 配置类型: memory(默认), jedis, redisson, redistemplate
## http 客户端配置(选填)
## # http客户端类型: http_client(默认), ok_http, jodd_http
wx.cp.config-storage.http-client-type=http_client
wx.cp.config-storage.http-proxy-host=
wx.cp.config-storage.http-proxy-port=
wx.cp.config-storage.http-proxy-username=
wx.cp.config-storage.http-proxy-password=
## 最大重试次数,默认:5 次,如果小于 0,则为 0
wx.cp.config-storage.max-retry-times=5
## 重试时间间隔步进,默认:1000 毫秒,如果小于 0,则为 1000
wx.cp.config-storage.retry-sleep-millis=1000
```
3. 支持自动注入的类型: `WxCpMultiServices`
4. 使用样例
```java
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.WxCpUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class DemoService {
@Autowired
private WxCpTpMultiServices wxCpTpMultiServices;
public void test() {
// 应用 1 的 WxCpService
WxCpService wxCpService1 = wxCpMultiServices.getWxCpService("tenantId1");
WxCpUserService userService1 = wxCpService1.getUserService();
userService1.getUserId("xxx");
// todo ...
// 应用 2 的 WxCpService
WxCpService wxCpService2 = wxCpMultiServices.getWxCpService("tenantId2");
WxCpUserService userService2 = wxCpService2.getUserService();
userService2.getUserId("xxx");
// todo ...
// 应用 3 的 WxCpService
WxCpService wxCpService3 = wxCpMultiServices.getWxCpService("tenantId3");
// 判断是否为空
if (wxCpService3 == null) {
// todo wxCpService3 为空,请先配置 tenantId3 企业微信应用参数
return;
}
WxCpUserService userService3 = wxCpService3.getUserService();
userService3.getUserId("xxx");
// todo ...
}
}
```
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>wx-java-cp-tp-multi-spring-boot-starter</artifactId>
<name>WxJava - Spring Boot Starter for WxCp::支持多账号配置</name>
<description>微信企业号开发的 Spring Boot Starter::支持多账号配置</description>
<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-cp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,16 @@
package com.binarywang.spring.starter.wxjava.cp.autoconfigure;
import com.binarywang.spring.starter.wxjava.cp.configuration.WxCpTpMultiServicesAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* 企业微信自动注册
*
* @author yl
* created on 2023/10/16
*/
@Configuration
@Import(WxCpTpMultiServicesAutoConfiguration.class)
public class WxCpTpMultiAutoConfiguration {
}
@@ -0,0 +1,27 @@
package com.binarywang.spring.starter.wxjava.cp.configuration;
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInJedisTpConfiguration;
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInMemoryTpConfiguration;
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInRedisTemplateTpConfiguration;
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInRedissonTpConfiguration;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* 企业微信平台相关服务自动注册
*
* @author yl
* created on 2023/10/16
*/
@Configuration
@EnableConfigurationProperties(WxCpTpMultiProperties.class)
@Import({
WxCpTpInJedisTpConfiguration.class,
WxCpTpInMemoryTpConfiguration.class,
WxCpTpInRedissonTpConfiguration.class,
WxCpTpInRedisTemplateTpConfiguration.class
})
public class WxCpTpMultiServicesAutoConfiguration {
}
@@ -0,0 +1,139 @@
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpSingleProperties;
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServicesImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceApacheHttpClientImpl;
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceImpl;
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceJoddHttpImpl;
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceOkHttpImpl;
import org.apache.commons.lang3.StringUtils;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* WxCpConfigStorage 抽象配置类
*
* @author yl
* created on 2023/10/16
*/
@RequiredArgsConstructor
@Slf4j
public abstract class AbstractWxCpTpConfiguration {
/**
*
* @param wxCpTpMultiProperties 应用列表配置
* @param services 用于支持,应用启动之后,可以调用这个接口添加新服务对象。主要是配置是从数据库中读取的
* @return
*/
public WxCpTpMultiServices wxCpMultiServices(WxCpTpMultiProperties wxCpTpMultiProperties,WxCpTpMultiServices services) {
Map<String, WxCpTpSingleProperties> corps = wxCpTpMultiProperties.getCorps();
if (corps == null || corps.isEmpty()) {
log.warn("企业微信应用参数未配置,通过 WxCpMultiServices#getWxCpTpService(\"tenantId\")获取实例将返回空");
return new WxCpTpMultiServicesImpl();
}
if (services == null) {
services = new WxCpTpMultiServicesImpl();
}
Set<Map.Entry<String, WxCpTpSingleProperties>> entries = corps.entrySet();
for (Map.Entry<String, WxCpTpSingleProperties> entry : entries) {
String tenantId = entry.getKey();
WxCpTpSingleProperties wxCpTpSingleProperties = entry.getValue();
WxCpTpDefaultConfigImpl storage = this.wxCpTpConfigStorage(wxCpTpMultiProperties);
this.configCorp(storage, wxCpTpSingleProperties);
this.configHttp(storage, wxCpTpMultiProperties.getConfigStorage());
WxCpTpService wxCpTpService = this.wxCpTpService(storage, wxCpTpMultiProperties.getConfigStorage());
if (services.getWxCpTpService(tenantId) == null) {
// 不存在的才会添加到服务列表中
services.addWxCpTpService(tenantId, wxCpTpService);
}
}
return services;
}
/**
* 配置 WxCpDefaultConfigImpl
*
* @param wxCpTpMultiProperties 参数
* @return WxCpDefaultConfigImpl
*/
protected abstract WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties);
private WxCpTpService wxCpTpService(WxCpTpConfigStorage wxCpTpConfigStorage, WxCpTpMultiProperties.ConfigStorage storage) {
WxCpTpMultiProperties.HttpClientType httpClientType = storage.getHttpClientType();
WxCpTpService cpTpService;
switch (httpClientType) {
case OK_HTTP:
cpTpService = new WxCpTpServiceOkHttpImpl();
break;
case JODD_HTTP:
cpTpService = new WxCpTpServiceJoddHttpImpl();
break;
case HTTP_CLIENT:
cpTpService = new WxCpTpServiceApacheHttpClientImpl();
break;
default:
cpTpService = new WxCpTpServiceImpl();
break;
}
cpTpService.setWxCpTpConfigStorage(wxCpTpConfigStorage);
int maxRetryTimes = storage.getMaxRetryTimes();
if (maxRetryTimes < 0) {
maxRetryTimes = 0;
}
int retrySleepMillis = storage.getRetrySleepMillis();
if (retrySleepMillis < 0) {
retrySleepMillis = 1000;
}
cpTpService.setRetrySleepMillis(retrySleepMillis);
cpTpService.setMaxRetryTimes(maxRetryTimes);
return cpTpService;
}
private void configCorp(WxCpTpDefaultConfigImpl config, WxCpTpSingleProperties wxCpTpSingleProperties) {
String corpId = wxCpTpSingleProperties.getCorpId();
String providerSecret = wxCpTpSingleProperties.getProviderSecret();
String suiteId = wxCpTpSingleProperties.getSuiteId();
String token = wxCpTpSingleProperties.getToken();
String suiteSecret = wxCpTpSingleProperties.getSuiteSecret();
// 企业微信,私钥,会话存档路径
config.setCorpId(corpId);
config.setProviderSecret(providerSecret);
config.setEncodingAESKey(wxCpTpSingleProperties.getEncodingAESKey());
config.setSuiteId(suiteId);
config.setToken(token);
config.setSuiteSecret(suiteSecret);
}
private void configHttp(WxCpTpDefaultConfigImpl config, WxCpTpMultiProperties.ConfigStorage storage) {
String httpProxyHost = storage.getHttpProxyHost();
Integer httpProxyPort = storage.getHttpProxyPort();
String httpProxyUsername = storage.getHttpProxyUsername();
String httpProxyPassword = storage.getHttpProxyPassword();
if (StringUtils.isNotBlank(httpProxyHost)) {
config.setHttpProxyHost(httpProxyHost);
if (httpProxyPort != null) {
config.setHttpProxyPort(httpProxyPort);
}
if (StringUtils.isNotBlank(httpProxyUsername)) {
config.setHttpProxyUsername(httpProxyUsername);
}
if (StringUtils.isNotBlank(httpProxyPassword)) {
config.setHttpProxyPassword(httpProxyPassword);
}
}
}
}
@@ -0,0 +1,78 @@
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiRedisProperties;
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpJedisConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpJedisConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* 自动装配基于 jedis 策略配置
*
* @author yl
* created on 2023/10/16
*/
@Configuration
@ConditionalOnProperty(
prefix = WxCpTpMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "jedis"
)
@RequiredArgsConstructor
public class WxCpTpInJedisTpConfiguration extends AbstractWxCpTpConfiguration {
private final WxCpTpMultiProperties wxCpTpMultiProperties;
private final ApplicationContext applicationContext;
@Bean
public WxCpTpMultiServices wxCpMultiServices() {
return this.wxCpMultiServices(wxCpTpMultiProperties,null);
}
@Override
protected WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties) {
return this.configRedis(wxCpTpMultiProperties);
}
private WxCpTpDefaultConfigImpl configRedis(WxCpTpMultiProperties wxCpTpMultiProperties) {
WxCpTpMultiRedisProperties wxCpTpMultiRedisProperties = wxCpTpMultiProperties.getConfigStorage().getRedis();
JedisPool jedisPool;
if (wxCpTpMultiRedisProperties != null && StringUtils.isNotEmpty(wxCpTpMultiRedisProperties.getHost())) {
jedisPool = getJedisPool(wxCpTpMultiProperties);
} else {
jedisPool = applicationContext.getBean(JedisPool.class);
}
return new WxCpTpJedisConfigImpl(jedisPool, wxCpTpMultiProperties.getConfigStorage().getKeyPrefix());
}
private JedisPool getJedisPool(WxCpTpMultiProperties wxCpTpMultiProperties) {
WxCpTpMultiProperties.ConfigStorage storage = wxCpTpMultiProperties.getConfigStorage();
WxCpTpMultiRedisProperties redis = storage.getRedis();
JedisPoolConfig config = new JedisPoolConfig();
if (redis.getMaxActive() != null) {
config.setMaxTotal(redis.getMaxActive());
}
if (redis.getMaxIdle() != null) {
config.setMaxIdle(redis.getMaxIdle());
}
if (redis.getMaxWaitMillis() != null) {
config.setMaxWaitMillis(redis.getMaxWaitMillis());
}
if (redis.getMinIdle() != null) {
config.setMinIdle(redis.getMinIdle());
}
config.setTestOnBorrow(true);
config.setTestWhileIdle(true);
return new JedisPool(config, redis.getHost(), redis.getPort(),
redis.getTimeout(), redis.getPassword(), redis.getDatabase());
}
}
@@ -0,0 +1,39 @@
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 自动装配基于内存策略配置
*
* @author yl
* created on 2023/10/16
*/
@Configuration
@ConditionalOnProperty(
prefix = WxCpTpMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "memory", matchIfMissing = true
)
@RequiredArgsConstructor
public class WxCpTpInMemoryTpConfiguration extends AbstractWxCpTpConfiguration {
private final WxCpTpMultiProperties wxCpTpMultiProperties;
@Bean
public WxCpTpMultiServices wxCpMultiServices() {
return this.wxCpMultiServices(wxCpTpMultiProperties,null);
}
@Override
protected WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties) {
return this.configInMemory();
}
private WxCpTpDefaultConfigImpl configInMemory() {
return new WxCpTpDefaultConfigImpl();
}
}
@@ -0,0 +1,45 @@
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpRedisTemplateConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpRedisTemplateConfigImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
/**
* 自动装配基于 redisTemplate 策略配置
*
* @author yl
* created on 2023/10/16
*/
@Configuration
@ConditionalOnProperty(
prefix = WxCpTpMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "redistemplate"
)
@RequiredArgsConstructor
public class WxCpTpInRedisTemplateTpConfiguration extends AbstractWxCpTpConfiguration {
private final WxCpTpMultiProperties wxCpTpMultiProperties;
private final ApplicationContext applicationContext;
@Bean
public WxCpTpMultiServices wxCpMultiServices() {
return this.wxCpMultiServices(wxCpTpMultiProperties,null);
}
@Override
protected WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties) {
return this.configRedisTemplate(wxCpTpMultiProperties);
}
private WxCpTpDefaultConfigImpl configRedisTemplate(WxCpTpMultiProperties wxCpTpMultiProperties) {
StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
return new WxCpTpRedisTemplateConfigImpl(redisTemplate, wxCpTpMultiProperties.getConfigStorage().getKeyPrefix());
}
}
@@ -0,0 +1,68 @@
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiRedisProperties;
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
import me.chanjar.weixin.cp.config.impl.AbstractWxCpTpInRedisConfigImpl;
import me.chanjar.weixin.cp.config.impl.WxCpTpRedissonConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.TransportMode;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 自动装配基于 redisson 策略配置
*
* @author yl
* created on 2023/10/16
*/
@Configuration
@ConditionalOnProperty(
prefix = WxCpTpMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "redisson"
)
@RequiredArgsConstructor
public class WxCpTpInRedissonTpConfiguration extends AbstractWxCpTpConfiguration {
private final WxCpTpMultiProperties wxCpTpMultiProperties;
private final ApplicationContext applicationContext;
@Bean
public WxCpTpMultiServices wxCpMultiServices() {
return this.wxCpMultiServices(wxCpTpMultiProperties,null);
}
@Override
protected WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties) {
return this.configRedisson(wxCpTpMultiProperties);
}
private WxCpTpDefaultConfigImpl configRedisson(WxCpTpMultiProperties wxCpTpMultiProperties) {
WxCpTpMultiRedisProperties redisProperties = wxCpTpMultiProperties.getConfigStorage().getRedis();
RedissonClient redissonClient;
if (redisProperties != null && StringUtils.isNotEmpty(redisProperties.getHost())) {
redissonClient = getRedissonClient(wxCpTpMultiProperties);
} else {
redissonClient = applicationContext.getBean(RedissonClient.class);
}
return new WxCpTpRedissonConfigImpl(redissonClient, wxCpTpMultiProperties.getConfigStorage().getKeyPrefix());
}
private RedissonClient getRedissonClient(WxCpTpMultiProperties wxCpTpMultiProperties) {
WxCpTpMultiProperties.ConfigStorage storage = wxCpTpMultiProperties.getConfigStorage();
WxCpTpMultiRedisProperties redis = storage.getRedis();
Config config = new Config();
config.useSingleServer()
.setAddress("redis://" + redis.getHost() + ":" + redis.getPort())
.setDatabase(redis.getDatabase())
.setPassword(redis.getPassword());
config.setTransportMode(TransportMode.NIO);
return Redisson.create(config);
}
}
@@ -0,0 +1,129 @@
package com.binarywang.spring.starter.wxjava.cp.properties;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* 企业微信多企业接入相关配置属性
*
* @author yl
* created on 2023/10/16
*/
@Data
@NoArgsConstructor
@ConfigurationProperties(prefix = WxCpTpMultiProperties.PREFIX)
public class WxCpTpMultiProperties implements Serializable {
private static final long serialVersionUID = -1569510477055668503L;
public static final String PREFIX = "wx.cp.tp";
private Map<String, WxCpTpSingleProperties> corps = new HashMap<>();
/**
* 配置存储策略,默认内存
*/
private ConfigStorage configStorage = new ConfigStorage();
@Data
@NoArgsConstructor
public static class ConfigStorage implements Serializable {
private static final long serialVersionUID = 4815731027000065434L;
/**
* 存储类型
*/
private StorageType type = StorageType.memory;
/**
* 指定key前缀
*/
private String keyPrefix = "wx:cp:tp";
/**
* redis连接配置
*/
@NestedConfigurationProperty
private WxCpTpMultiRedisProperties redis = new WxCpTpMultiRedisProperties();
/**
* http客户端类型.
*/
private HttpClientType httpClientType = HttpClientType.HTTP_CLIENT;
/**
* http代理主机
*/
private String httpProxyHost;
/**
* http代理端口
*/
private Integer httpProxyPort;
/**
* http代理用户名
*/
private String httpProxyUsername;
/**
* http代理密码
*/
private String httpProxyPassword;
/**
* http 请求最大重试次数
* <pre>
* {@link me.chanjar.weixin.cp.api.WxCpService#setMaxRetryTimes(int)}
* {@link me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl#setMaxRetryTimes(int)}
* </pre>
*/
private int maxRetryTimes = 5;
/**
* http 请求重试间隔
* <pre>
* {@link me.chanjar.weixin.cp.api.WxCpService#setRetrySleepMillis(int)}
* {@link me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl#setRetrySleepMillis(int)}
* </pre>
*/
private int retrySleepMillis = 1000;
}
public enum StorageType {
/**
* 内存
*/
memory,
/**
* jedis
*/
jedis,
/**
* redisson
*/
redisson,
/**
* redistemplate
*/
redistemplate
}
public enum HttpClientType {
/**
* HttpClient
*/
HTTP_CLIENT,
/**
* OkHttp
*/
OK_HTTP,
/**
* JoddHttp
*/
JODD_HTTP
}
}
@@ -0,0 +1,48 @@
package com.binarywang.spring.starter.wxjava.cp.properties;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* Redis配置.
*
* @author yl
* created on 2023/10/16
*/
@Data
@NoArgsConstructor
public class WxCpTpMultiRedisProperties implements Serializable {
private static final long serialVersionUID = -5924815351660074401L;
/**
* 主机地址.
*/
private String host;
/**
* 端口号.
*/
private int port = 6379;
/**
* 密码.
*/
private String password;
/**
* 超时.
*/
private int timeout = 2000;
/**
* 数据库.
*/
private int database = 0;
private Integer maxActive;
private Integer maxIdle;
private Integer maxWaitMillis;
private Integer minIdle;
}
@@ -0,0 +1,43 @@
package com.binarywang.spring.starter.wxjava.cp.properties;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 企业微信企业相关配置属性
*
* @author yl
* created on 2023/10/16
*/
@Data
@NoArgsConstructor
public class WxCpTpSingleProperties implements Serializable {
private static final long serialVersionUID = -7502823825007859418L;
/**
* 微信企业号 corpId
*/
private String corpId;
/**
* 微信企业号 服务商 providerSecret
*/
private String providerSecret;
/**
* 微信企业号应用 token
*/
private String token;
private String encodingAESKey;
/**
* 微信企业号 第三方 应用 ID
*/
private String suiteId;
/**
* 微信企业号应用
*/
private String suiteSecret;
}
@@ -0,0 +1,29 @@
package com.binarywang.spring.starter.wxjava.cp.service;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
/**
* 企业微信 {@link WxCpTpService} 所有实例存放类.
*
* @author yl
* created on 2023/10/16
*/
public interface WxCpTpMultiServices {
/**
* 通过租户 Id 获取 WxCpTpService
*
* @param tenantId 租户 Id
* @return WxCpTpService
*/
WxCpTpService getWxCpTpService(String tenantId);
void addWxCpTpService(String tenantId, WxCpTpService wxCpService);
/**
* 根据租户 Id,从列表中移除一个 WxCpTpService 实例
*
* @param tenantId 租户 Id
*/
void removeWxCpTpService(String tenantId);
}
@@ -0,0 +1,44 @@
package com.binarywang.spring.starter.wxjava.cp.service;
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 企业微信 {@link WxCpTpMultiServices} 默认实现
*
* @author yl
* created on 2023/10/16
*/
public class WxCpTpMultiServicesImpl implements WxCpTpMultiServices {
private final Map<String, WxCpTpService> services = new ConcurrentHashMap<>();
/**
* 通过租户 Id 获取 WxCpTpService
*
* @param tenantId 租户 Id
* @return WxCpTpService
*/
@Override
public WxCpTpService getWxCpTpService(String tenantId) {
return this.services.get(tenantId);
}
/**
* 根据租户 Id,添加一个 WxCpTpService 到列表
*
* @param tenantId 租户 Id
* @param wxCpService WxCpTpService 实例
*/
@Override
public void addWxCpTpService(String tenantId, WxCpTpService wxCpService) {
this.services.put(tenantId, wxCpService);
}
@Override
public void removeWxCpTpService(String tenantId) {
this.services.remove(tenantId);
}
}
@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.binarywang.spring.starter.wxjava.cp.autoconfigure.WxCpTpMultiAutoConfiguration
@@ -0,0 +1 @@
com.binarywang.spring.starter.wxjava.cp.autoconfigure.WxCpTpMultiAutoConfiguration
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -2,6 +2,7 @@ package com.binarywang.spring.starter.wxjava.miniapp.configuration;
import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInJedisConfiguration;
import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInMemoryConfiguration;
import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInRedisTemplateConfiguration;
import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInRedissonConfiguration;
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -17,9 +18,10 @@ import org.springframework.context.annotation.Import;
@Configuration
@EnableConfigurationProperties(WxMaMultiProperties.class)
@Import({
WxMaInJedisConfiguration.class,
WxMaInMemoryConfiguration.class,
WxMaInRedissonConfiguration.class,
WxMaInJedisConfiguration.class,
WxMaInMemoryConfiguration.class,
WxMaInRedissonConfiguration.class,
WxMaInRedisTemplateConfiguration.class
})
public class WxMaMultiServiceConfiguration {
}
@@ -108,12 +108,12 @@ public abstract class AbstractWxMaConfiguration {
return wxMaService;
}
private void configApp(WxMaDefaultConfigImpl config, WxMaSingleProperties corpProperties) {
String appId = corpProperties.getAppId();
String appSecret = corpProperties.getAppSecret();
String token = corpProperties.getToken();
String aesKey = corpProperties.getAesKey();
boolean useStableAccessToken = corpProperties.isUseStableAccessToken();
private void configApp(WxMaDefaultConfigImpl config, WxMaSingleProperties properties) {
String appId = properties.getAppId();
String appSecret = properties.getAppSecret();
String token = properties.getToken();
String aesKey = properties.getAesKey();
boolean useStableAccessToken = properties.isUseStableAccessToken();
config.setAppid(appId);
config.setSecret(appSecret);
@@ -123,7 +123,10 @@ public abstract class AbstractWxMaConfiguration {
if (StringUtils.isNotBlank(aesKey)) {
config.setAesKey(aesKey);
}
config.setMsgDataFormat(properties.getMsgDataFormat());
config.useStableAccessToken(useStableAccessToken);
config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
}
private void configHttp(WxMaDefaultConfigImpl config, WxMaMultiProperties.ConfigStorage storage) {
@@ -0,0 +1,43 @@
package com.binarywang.spring.starter.wxjava.miniapp.configuration.services;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices;
import lombok.RequiredArgsConstructor;
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
/**
* 自动装配基于 redisTemplate 策略配置
*
* @author <a href="mailto:huangbing0730@gmail">hb0730</a> 2025/9/10
*/
@Configuration
@ConditionalOnProperty(prefix = WxMaMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "redis_template")
@RequiredArgsConstructor
public class WxMaInRedisTemplateConfiguration extends AbstractWxMaConfiguration {
private final WxMaMultiProperties wxMaMultiProperties;
private final ApplicationContext applicationContext;
@Bean
public WxMaMultiServices wxMaMultiServices() {
return this.wxMaMultiServices(wxMaMultiProperties);
}
@Override
protected WxMaDefaultConfigImpl wxMaConfigStorage(WxMaMultiProperties wxMaMultiProperties) {
return this.configRedisTemplate(wxMaMultiProperties);
}
private WxMaDefaultConfigImpl configRedisTemplate(WxMaMultiProperties wxMaMultiProperties) {
StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
RedisTemplateWxRedisOps wxRedisOps = new RedisTemplateWxRedisOps(redisTemplate);
return new WxMaRedisBetterConfigImpl(wxRedisOps, wxMaMultiProperties.getConfigStorage().getKeyPrefix());
}
}
@@ -33,8 +33,25 @@ public class WxMaSingleProperties implements Serializable {
*/
private String aesKey;
/**
* 消息格式,XML或者JSON.
*/
private String msgDataFormat;
/**
* 是否使用稳定版 Access Token
*/
private boolean useStableAccessToken = false;
/**
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String apiHostUrl;
/**
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
* 例如:http://proxy.company.com:8080/oauth/token
*/
private String accessTokenUrl;
}
@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -2,6 +2,8 @@ package com.binarywang.spring.starter.wxjava.miniapp.config.storage;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
import org.apache.commons.lang3.StringUtils;
/**
@@ -10,12 +12,15 @@ import org.apache.commons.lang3.StringUtils;
public abstract class AbstractWxMaConfigStorageConfiguration {
protected WxMaDefaultConfigImpl config(WxMaDefaultConfigImpl config, WxMaProperties properties) {
WxMaProperties.ConfigStorage storage = properties.getConfigStorage();
config.setAppid(StringUtils.trimToNull(properties.getAppid()));
config.setSecret(StringUtils.trimToNull(properties.getSecret()));
config.setToken(StringUtils.trimToNull(properties.getToken()));
config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
config.useStableAccessToken(properties.isUseStableAccessToken());
config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
WxMaProperties.ConfigStorage configStorageProperties = properties.getConfigStorage();
config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
@@ -25,6 +30,19 @@ public abstract class AbstractWxMaConfigStorageConfiguration {
config.setHttpProxyPort(configStorageProperties.getHttpProxyPort());
}
// 设置自定义的HttpClient超时配置
ApacheHttpClientBuilder clientBuilder = config.getApacheHttpClientBuilder();
if (clientBuilder == null) {
clientBuilder = DefaultApacheHttpClientBuilder.get();
}
if (clientBuilder instanceof DefaultApacheHttpClientBuilder) {
DefaultApacheHttpClientBuilder defaultBuilder = (DefaultApacheHttpClientBuilder) clientBuilder;
defaultBuilder.setConnectionTimeout(storage.getConnectionTimeout());
defaultBuilder.setSoTimeout(storage.getSoTimeout());
defaultBuilder.setConnectionRequestTimeout(storage.getConnectionRequestTimeout());
config.setApacheHttpClientBuilder(defaultBuilder);
}
int maxRetryTimes = configStorageProperties.getMaxRetryTimes();
if (configStorageProperties.getMaxRetryTimes() < 0) {
maxRetryTimes = 0;
@@ -49,6 +49,18 @@ public class WxMaProperties {
*/
private boolean useStableAccessToken = false;
/**
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String apiHostUrl;
/**
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
* 例如:http://proxy.company.com:8080/oauth/token
*/
private String accessTokenUrl;
/**
* 存储策略
*/
@@ -112,6 +124,21 @@ public class WxMaProperties {
* </pre>
*/
private int maxRetryTimes = 5;
/**
* 连接超时时间,单位毫秒
*/
private int connectionTimeout = 5000;
/**
* 读数据超时时间,即socketTimeout,单位毫秒
*/
private int soTimeout = 5000;
/**
* 从连接池获取链接的超时时间,单位毫秒
*/
private int connectionRequestTimeout = 5000;
}
}
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -44,6 +44,11 @@
<artifactId>okhttp</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
@@ -7,10 +7,7 @@ import com.binarywang.spring.starter.wxjava.mp.service.WxMpMultiServicesImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.api.impl.WxMpServiceJoddHttpImpl;
import me.chanjar.weixin.mp.api.impl.WxMpServiceOkHttpImpl;
import me.chanjar.weixin.mp.api.impl.*;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.WxMpHostConfig;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
@@ -91,6 +88,9 @@ public abstract class AbstractWxMpConfiguration {
case HTTP_CLIENT:
wxMpService = new WxMpServiceHttpClientImpl();
break;
case HTTP_COMPONENTS:
wxMpService = new WxMpServiceHttpComponentsImpl();
break;
default:
wxMpService = new WxMpServiceImpl();
break;
@@ -142,6 +142,10 @@ public class WxMpMultiProperties implements Serializable {
* HttpClient
*/
HTTP_CLIENT,
/**
* HttpComponents
*/
HTTP_COMPONENTS,
/**
* OkHttp
*/
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -39,6 +39,11 @@
<artifactId>okhttp</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
@@ -4,6 +4,7 @@ import com.binarywang.spring.starter.wxjava.mp.enums.HttpClientType;
import com.binarywang.spring.starter.wxjava.mp.properties.WxMpProperties;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpComponentsImpl;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.api.impl.WxMpServiceJoddHttpImpl;
import me.chanjar.weixin.mp.api.impl.WxMpServiceOkHttpImpl;
@@ -35,6 +36,9 @@ public class WxMpServiceAutoConfiguration {
case HttpClient:
wxMpService = newWxMpServiceHttpClientImpl();
break;
case HttpComponents:
wxMpService = newWxMpServiceHttpComponentsImpl();
break;
default:
wxMpService = newWxMpServiceImpl();
break;
@@ -60,4 +64,8 @@ public class WxMpServiceAutoConfiguration {
return new WxMpServiceJoddHttpImpl();
}
private WxMpService newWxMpServiceHttpComponentsImpl() {
return new WxMpServiceHttpComponentsImpl();
}
}
@@ -9,6 +9,8 @@ import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.redis.JedisWxRedisOps;
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
import me.chanjar.weixin.common.redis.WxRedisOps;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.WxMpHostConfig;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
@@ -122,6 +124,19 @@ public class WxMpStorageAutoConfiguration {
config.setSecret(properties.getSecret());
config.setToken(properties.getToken());
config.setAesKey(properties.getAesKey());
WxMpProperties.ConfigStorage storage = properties.getConfigStorage();
// 设置自定义的HttpClient超时配置
ApacheHttpClientBuilder clientBuilder = config.getApacheHttpClientBuilder();
if (clientBuilder == null) {
clientBuilder = DefaultApacheHttpClientBuilder.get();
}
if (clientBuilder instanceof DefaultApacheHttpClientBuilder) {
DefaultApacheHttpClientBuilder defaultBuilder = (DefaultApacheHttpClientBuilder) clientBuilder;
defaultBuilder.setConnectionTimeout(storage.getConnectionTimeout());
defaultBuilder.setSoTimeout(storage.getSoTimeout());
defaultBuilder.setConnectionRequestTimeout(storage.getConnectionRequestTimeout());
config.setApacheHttpClientBuilder(defaultBuilder);
}
config.setUseStableAccessToken(wxMpProperties.isUseStableAccessToken());
config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
config.setHttpProxyUsername(configStorageProperties.getHttpProxyUsername());
@@ -19,4 +19,8 @@ public enum HttpClientType {
* JoddHttp.
*/
JoddHttp,
/**
* HttpComponents (Apache HttpClient 5.x).
*/
HttpComponents,
}
@@ -102,6 +102,21 @@ public class WxMpProperties {
*/
private String httpProxyPassword;
/**
* 连接超时时间,单位毫秒
*/
private int connectionTimeout = 5000;
/**
* 读数据超时时间,即socketTimeout,单位毫秒
*/
private int soTimeout = 5000;
/**
* 从连接池获取链接的超时时间,单位毫秒
*/
private int connectionRequestTimeout = 5000;
}
}
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -28,6 +28,7 @@ public class WxOpenServiceAutoConfiguration {
}
@Bean
@ConditionalOnMissingBean
public WxOpenMessageRouter wxOpenMessageRouter(WxOpenService wxOpenService) {
return new WxOpenMessageRouter(wxOpenService);
}
@@ -1,7 +1,10 @@
package com.binarywang.spring.starter.wxjava.open.config.storage;
import com.binarywang.spring.starter.wxjava.open.properties.WxOpenProperties;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
import me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage;
import org.apache.commons.lang3.StringUtils;
/**
* @author yl
@@ -28,6 +31,24 @@ public abstract class AbstractWxOpenConfigStorageConfiguration {
}
config.setRetrySleepMillis(retrySleepMillis);
config.setMaxRetryTimes(maxRetryTimes);
// 设置URL配置
config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
// 设置自定义的HttpClient超时配置
ApacheHttpClientBuilder clientBuilder = config.getApacheHttpClientBuilder();
if (clientBuilder == null) {
clientBuilder = DefaultApacheHttpClientBuilder.get();
}
if (clientBuilder instanceof DefaultApacheHttpClientBuilder) {
DefaultApacheHttpClientBuilder defaultBuilder = (DefaultApacheHttpClientBuilder) clientBuilder;
defaultBuilder.setConnectionTimeout(storage.getConnectionTimeout());
defaultBuilder.setSoTimeout(storage.getSoTimeout());
defaultBuilder.setConnectionRequestTimeout(storage.getConnectionRequestTimeout());
config.setApacheHttpClientBuilder(defaultBuilder);
}
return config;
}
}
@@ -40,6 +40,18 @@ public class WxOpenProperties {
*/
private String aesKey;
/**
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String apiHostUrl;
/**
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
* 例如:http://proxy.company.com:8080/oauth/token
*/
private String accessTokenUrl;
/**
* 存储策略.
*/
@@ -108,6 +120,21 @@ public class WxOpenProperties {
*/
private int maxRetryTimes = 5;
/**
* 连接超时时间,单位毫秒
*/
private int connectionTimeout = 5000;
/**
* 读数据超时时间,即socketTimeout,单位毫秒
*/
private int soTimeout = 5000;
/**
* 从连接池获取链接的超时时间,单位毫秒
*/
private int connectionRequestTimeout = 5000;
}
public enum StorageType {
@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -50,13 +50,20 @@ public class WxPayAutoConfiguration {
payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
payConfig.setUseSandboxEnv(this.properties.isUseSandboxEnv());
payConfig.setNotifyUrl(StringUtils.trimToNull(this.properties.getNotifyUrl()));
//以下是apiv3以及支付分相关
payConfig.setServiceId(StringUtils.trimToNull(this.properties.getServiceId()));
payConfig.setPayScoreNotifyUrl(StringUtils.trimToNull(this.properties.getPayScoreNotifyUrl()));
payConfig.setPayScorePermissionNotifyUrl(StringUtils.trimToNull(this.properties.getPayScorePermissionNotifyUrl()));
payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath()));
payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));
payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getCertSerialNo()));
payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiv3Key()));
payConfig.setPublicKeyId(StringUtils.trimToNull(this.properties.getPublicKeyId()));
payConfig.setPublicKeyPath(StringUtils.trimToNull(this.properties.getPublicKeyPath()));
payConfig.setApiHostUrl(StringUtils.trimToNull(this.properties.getApiHostUrl()));
payConfig.setStrictlyNeedWechatPaySerial(this.properties.isStrictlyNeedWechatPaySerial());
payConfig.setFullPublicKeyModel(this.properties.isFullPublicKeyModel());
wxPayService.setConfig(payConfig);
return wxPayService;
@@ -59,11 +59,21 @@ public class WxPayProperties {
*/
private String apiv3Key;
/**
* 微信支付异步回调地址,通知url必须为直接可访问的url,不能携带参数
*/
private String notifyUrl;
/**
* 微信支付分回调地址
*/
private String payScoreNotifyUrl;
/**
* 微信支付分授权回调地址
*/
private String payScorePermissionNotifyUrl;
/**
* apiv3 商户apiclient_key.pem
*/
@@ -73,11 +83,37 @@ public class WxPayProperties {
* apiv3 商户apiclient_cert.pem
*/
private String privateCertPath;
/**
* 公钥ID
*/
private String publicKeyId;
/**
* pub_key.pem证书文件的绝对路径或者以classpath:开头的类路径.
*/
private String publicKeyPath;
/**
* 微信支付是否使用仿真测试环境.
* 默认不使用
*/
private boolean useSandboxEnv;
/**
* 自定义API主机地址,用于替换默认的 https://api.mch.weixin.qq.com
* 例如:http://proxy.company.com:8080
*/
private String apiHostUrl;
/**
* 是否将全部v3接口的请求都添加Wechatpay-Serial请求头,默认不添加
*/
private boolean strictlyNeedWechatPaySerial = false;
/**
* 是否完全使用公钥模式(用以微信从平台证书到公钥的灰度切换),默认不使用
*/
private boolean fullPublicKeyModel = false;
}
@@ -3,7 +3,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -20,6 +20,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
@@ -80,7 +81,7 @@ public class WxQidianStorageAutoConfiguration {
}
private WxQidianConfigStorage jedisConfigStorage() {
Pool jedisPool;
Pool<Jedis> jedisPool;
if (StringUtils.isNotEmpty(redisHost) || StringUtils.isNotEmpty(redisHost2)) {
jedisPool = getJedisPool();
} else {
@@ -136,7 +137,7 @@ public class WxQidianStorageAutoConfiguration {
}
}
private Pool getJedisPool() {
private Pool<Jedis> getJedisPool() {
WxQidianProperties.ConfigStorage storage = wxQidianProperties.getConfigStorage();
RedisProperties redis = storage.getRedis();
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<artifactId>weixin-graal</artifactId>
+7 -2
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.1.B</version>
<version>4.8.0</version>
</parent>
<artifactId>weixin-java-channel</artifactId>
@@ -14,7 +14,7 @@
<description>微信视频号/微信小店 Java SDK</description>
<properties>
<jackson.version>2.18.1</jackson.version>
<jackson.version>2.18.4</jackson.version>
</properties>
<dependencies>
@@ -29,6 +29,11 @@
<artifactId>jodd-http</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@@ -131,5 +131,5 @@ public interface BaseWxChannelService extends WxService {
*
* @return . request http
*/
RequestHttp getRequestHttp();
RequestHttp<?, ?> getRequestHttp();
}
@@ -2,10 +2,8 @@ package me.chanjar.weixin.channel.api;
import java.util.List;
import me.chanjar.weixin.channel.bean.after.AfterSaleInfoResponse;
import me.chanjar.weixin.channel.bean.after.AfterSaleListResponse;
import me.chanjar.weixin.channel.bean.after.AfterSaleReasonResponse;
import me.chanjar.weixin.channel.bean.after.AfterSaleRejectReasonResponse;
import me.chanjar.weixin.channel.bean.after.*;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
import me.chanjar.weixin.channel.bean.complaint.ComplaintOrderResponse;
import me.chanjar.weixin.common.error.WxErrorException;
@@ -26,10 +24,22 @@ public interface WxChannelAfterSaleService {
* @return 售后单列表
*
* @throws WxErrorException 异常
* @deprecated 使用 {@link WxChannelAfterSaleService#listIds(AfterSaleListParam)}
*/
@Deprecated
AfterSaleListResponse listIds(Long beginCreateTime, Long endCreateTime, String nextKey)
throws WxErrorException;
/**
* 获取售后单列表
*
* @param param 参数
* @return 售后单列表
*
* @throws WxErrorException 异常
*/
AfterSaleListResponse listIds(AfterSaleListParam param) throws WxErrorException;
/**
* 获取售后单详情
*
@@ -136,4 +146,41 @@ public interface WxChannelAfterSaleService {
* @throws WxErrorException 异常
*/
AfterSaleRejectReasonResponse getRejectReason() throws WxErrorException;
/**
* 换货发货
* 文档地址:https://developers.weixin.qq.com/doc/store/shop/API/channels-shop-aftersale/api_acceptexchangereship.html
*
* @param afterSaleOrderId 售后单号
* @param waybillId 快递单号
* @param deliveryId 快递公司id
* @return BaseResponse
*
* @throws WxErrorException 异常
*/
WxChannelBaseResponse acceptExchangeReship(String afterSaleOrderId, String waybillId, String deliveryId) throws WxErrorException;
/**
* 换货拒绝发货
* 文档地址:https://developers.weixin.qq.com/doc/store/shop/API/channels-shop-aftersale/api_rejectexchangereship.html
*
* @param afterSaleOrderId 售后单号
* @param rejectReason 拒绝原因具体描述 ,可使用默认描述,也可以自定义描述
* @param rejectReasonType 拒绝原因枚举值
* @param rejectCertificates 退款凭证,可使用图片上传接口获取media_id(数据类型填0)
* @return BaseResponse
*
* @throws WxErrorException 异常
*/
WxChannelBaseResponse rejectExchangeReship(String afterSaleOrderId, String rejectReason, Integer rejectReasonType, List<String> rejectCertificates) throws WxErrorException;
/**
* 商家协商
* 文档地址:https://developers.weixin.qq.com/doc/store/shop/API/channels-shop-aftersale/api_merchantupdateaftersale.html
* @param param 参数
* @return BaseResponse
*
* @throws WxErrorException 异常
*/
WxChannelBaseResponse merchantUpdateAfterSale(AfterSaleMerchantUpdateParam param) throws WxErrorException;
}
@@ -34,6 +34,17 @@ public interface WxChannelOrderService {
*/
OrderInfoResponse getOrder(String orderId) throws WxErrorException;
/**
* 获取订单详情
*
* @param orderId 订单id
* @param encodeSensitiveInfo 是否编码敏感信息
* @return 订单详情
*
* @throws WxErrorException 异常
*/
OrderInfoResponse getOrder(String orderId, Boolean encodeSensitiveInfo) throws WxErrorException;
/**
* 获取订单列表
*
@@ -128,7 +139,7 @@ public interface WxChannelOrderService {
WxChannelBaseResponse closeOrder(String orderId);
/**
* 获取快递公司列表
* 获取快递公司列表-旧
*
* @return 快递公司列表
*
@@ -136,6 +147,16 @@ public interface WxChannelOrderService {
*/
DeliveryCompanyResponse listDeliveryCompany() throws WxErrorException;
/**
* 获取快递公司列表
*
* @param ewaybillOnly 是否仅返回支持电子面单功能的快递公司
* @return 快递公司列表
*
* @throws WxErrorException 异常
*/
DeliveryCompanyResponse listDeliveryCompany(Boolean ewaybillOnly) throws WxErrorException;
/**
* 订单发货
*
@@ -15,43 +15,84 @@ public interface WxLeaguePromoterService {
/**
* 新增达人
*
* @param finderId 视频号finder_id
* @param finderId 视频号finder_id,待废除
* @return 结果
* @deprecated 使用 {@link #addPromoterV2(String)}
*/
@Deprecated
WxChannelBaseResponse addPromoter(String finderId) throws WxErrorException;
/**
* 编辑达人
*
* @param finderId 视频号finder_id
* @param finderId 视频号finder_id,待废除
* @param type 操作 1取消邀请 2结束合作
* @return 结果
* @deprecated 使用 {@link #updatePromoterV2(String, int)}
*/
@Deprecated
WxChannelBaseResponse updatePromoter(String finderId, int type) throws WxErrorException;
/**
* 删除达人
*
* @param finderId 视频号finder_id
* @param finderId 视频号finder_id,待废除
* @return 结果
* @deprecated 使用 {@link #deletePromoterV2(String)}
*/
@Deprecated
WxChannelBaseResponse deletePromoter(String finderId) throws WxErrorException;
/**
* 获取达人详情信息
*
* @param finderId 视频号finder_id
* @param finderId 视频号finder_id,待废除
* @return 结果
* @deprecated 使用 {@link #getPromoterInfoV2(String)}
*/
@Deprecated
PromoterInfoResponse getPromoterInfo(String finderId) throws WxErrorException;
/**
* 获取达人列表
*
* @param pageIndex 页面下标,下标从1开始,默认为1
* @param pageSize 单页达人数(不超过200)
* @param status 拉取该状态下的达人列表
* @return 结果
*/
PromoterListResponse listPromoter(Integer pageIndex, Integer pageSize, Integer status) throws WxErrorException;
/**
* 新增达人
*
* @param promoterId 达人带货id
* @return 结果
*/
WxChannelBaseResponse addPromoterV2(String promoterId) throws WxErrorException;
/**
* 编辑达人
*
* @param promoterId 达人带货id
* @param type 操作 1取消邀请 2结束合作
* @return 结果
*/
WxChannelBaseResponse updatePromoterV2(String promoterId, int type) throws WxErrorException;
/**
* 删除达人
*
* @param promoterId 达人带货id
* @return 结果
*/
WxChannelBaseResponse deletePromoterV2(String promoterId) throws WxErrorException;
/**
* 获取达人详情信息
*
* @param promoterId 达人带货id
* @return 结果
*/
PromoterInfoResponse getPromoterInfoV2(String promoterId) throws WxErrorException;
/**
* 获取达人列表
*
* @param pageIndex 页面下标,下标从1开始,默认为1
* @param pageSize 单页达人数(不超过200)
* @param status 拉取该状态下的达人列表
* @return 结果
*/
PromoterListResponse listPromoter(Integer pageIndex, Integer pageSize, Integer status) throws WxErrorException;
}
@@ -66,7 +66,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
private int maxRetryTimes = 5;
@Override
public RequestHttp getRequestHttp() {
public RequestHttp<H, P> getRequestHttp() {
return this;
}
@@ -75,7 +75,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
try {
return SHA1.gen(this.getConfig().getToken(), timestamp, nonce).equals(signature);
} catch (Exception e) {
log.error("Checking signature failed, and the reason is :" + e.getMessage());
log.error("Checking signature failed, and the reason is :{}", e.getMessage());
return false;
}
}
@@ -276,7 +276,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
* @throws WxErrorException 异常
*/
protected String extractAccessToken(String resultContent) throws WxErrorException {
log.debug("access-token response: " + resultContent);
log.debug("access-token response: {}", resultContent);
WxChannelConfig config = this.getConfig();
WxError error = WxError.fromJson(resultContent, WxType.Channel);
if (error.getErrorCode() != 0) {
@@ -28,7 +28,7 @@ import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Assist
public class WxAssistantServiceImpl implements WxAssistantService {
/** 微信商店服务 */
private final BaseWxChannelServiceImpl shopService;
private final BaseWxChannelServiceImpl<?, ?> shopService;
@Override
public WxChannelBaseResponse addWindowProduct(AddWindowProductRequest req) throws WxErrorException {
String resJson = shopService.post(ADD_WINDOW_PRODUCT_URL, "{}");
@@ -29,9 +29,9 @@ import me.chanjar.weixin.common.error.WxErrorException;
public class WxChannelAddressServiceImpl implements WxChannelAddressService {
/** 微信商店服务 */
private final BaseWxChannelServiceImpl shopService;
private final BaseWxChannelServiceImpl<?, ?> shopService;
public WxChannelAddressServiceImpl(BaseWxChannelServiceImpl shopService) {
public WxChannelAddressServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
this.shopService = shopService;
}
@@ -22,17 +22,25 @@ import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Compla
@Slf4j
public class WxChannelAfterSaleServiceImpl implements WxChannelAfterSaleService {
/** 微信商店服务 */
private final BaseWxChannelServiceImpl shopService;
/**
* 微信商店服务
*/
private final BaseWxChannelServiceImpl<?, ?> shopService;
public WxChannelAfterSaleServiceImpl(BaseWxChannelServiceImpl shopService) {
public WxChannelAfterSaleServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
this.shopService = shopService;
}
@Override
public AfterSaleListResponse listIds(Long beginCreateTime, Long endCreateTime, String nextKey)
throws WxErrorException {
AfterSaleListParam param = new AfterSaleListParam(beginCreateTime, endCreateTime, nextKey);
AfterSaleListParam param = new AfterSaleListParam(beginCreateTime, endCreateTime, null, null, nextKey);
String resJson = shopService.post(AFTER_SALE_LIST_URL, param);
return ResponseUtils.decode(resJson, AfterSaleListResponse.class);
}
@Override
public AfterSaleListResponse listIds(AfterSaleListParam param) throws WxErrorException {
String resJson = shopService.post(AFTER_SALE_LIST_URL, param);
return ResponseUtils.decode(resJson, AfterSaleListResponse.class);
}
@@ -101,4 +109,25 @@ public class WxChannelAfterSaleServiceImpl implements WxChannelAfterSaleService
String resJson = shopService.post(AFTER_SALE_REJECT_REASON_GET_URL, "{}");
return ResponseUtils.decode(resJson, AfterSaleRejectReasonResponse.class);
}
@Override
public WxChannelBaseResponse acceptExchangeReship(String afterSaleOrderId, String waybillId, String deliveryId) throws WxErrorException {
AfterSaleAcceptExchangeReshipParam param = new AfterSaleAcceptExchangeReshipParam(afterSaleOrderId, waybillId, deliveryId);
String resJson = shopService.post(AFTER_SALE_ACCEPT_EXCHANGE_RESHIP_URL, param);
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}
@Override
public WxChannelBaseResponse rejectExchangeReship(String afterSaleOrderId, String rejectReason, Integer rejectReasonType, List<String> rejectCertificates) throws WxErrorException {
AfterSaleRejectExchangeReshipParam param = new AfterSaleRejectExchangeReshipParam(afterSaleOrderId, rejectReason, rejectReasonType, rejectCertificates);
String resJson = shopService.post(AFTER_SALE_REJECT_EXCHANGE_RESHIP_URL, param);
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}
@Override
public WxChannelBaseResponse merchantUpdateAfterSale(AfterSaleMerchantUpdateParam param) throws WxErrorException {
String resJson = shopService.post(AFTER_SALE_MERCHANT_UPDATE_URL, param);
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
}
}

Some files were not shown because too many files have changed in this diff Show More