152 Commits

Author SHA1 Message Date
Binary Wang
fd3bbde725 🔖 发布 4.7.9.B 测试版本
Some checks failed
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 📝 为现有的企业微信流程审批功能添加完整的使用文档
Some checks failed
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 修复空指针问题
Some checks failed
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字段
Some checks failed
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接口注释文档
Some checks failed
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
Some checks failed
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 测试版本
Some checks failed
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 修复tryLockunlock中针对Key的序列化方式不一致导致无法unlock的问题
Some checks failed
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字段
Some checks failed
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 修复tryLockunlock中针对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
dengfengfeng
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 【微信支付】 修复平台收付通 - 合单支付 - 关闭订单接口,增加缺少的两个参数
Some checks failed
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
Some checks failed
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 握手失败问题
Some checks failed
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 🎨 修复错误的变量命名
Some checks are pending
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 🆕 【小程序】增加小程序基本信息通知事件相关的属性
Some checks failed
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类,抽取常量,优化重复代码
Some checks are pending
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 🎨 【公众号】删除已下线的新增删除永久图文素材的接口
Some checks failed
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
zhoushi1
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
Some checks failed
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 🎨 修复单元测试代码
Some checks failed
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 测试版本
Some checks are pending
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的位置
Some checks failed
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【视频号】微信小店更新售后、订单详情等返回参数,并修改获取售后单列表和获取快递公司列表等接口的参数
Some checks failed
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时私钥初始化失败的问题
Some checks failed
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代替
Some checks failed
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
796 changed files with 28614 additions and 4379 deletions

13
.github/agents/my-agent.agent.md vendored Normal file
View File

@@ -0,0 +1,13 @@
---
# 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
请使用中文输出思考过程和总结包括PR标题提交commit信息也要使用中文

202
.github/copilot-instructions.md vendored Normal file
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
.github/workflows vendored
View File

@@ -1,4 +0,0 @@
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

94
.github/workflows/maven-publish.yml vendored Normal file
View File

@@ -0,0 +1,94 @@
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 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 }}

142
README.md
View File

@@ -1,77 +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="FeaturedHelloGitHub" 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="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" valign="middle" colspan="1">
<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" 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 align="center" 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="center" 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="FeaturedHelloGitHub" 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
--------------------------------
### 其他说明
@@ -89,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>
@@ -106,6 +106,13 @@
- 企业微信:`weixin-java-cp`
- 微信视频号/微信小店:`weixin-java-channel`
**注意**
- **移动应用开发**如果你的移动应用iOS/Android App需要接入微信登录、分享等功能
- 微信登录(网页授权):使用 `weixin-java-open` 模块,在服务端处理 OAuth 授权
- 微信支付:使用 `weixin-java-pay` 模块
- 客户端集成需使用微信官方提供的移动端SDKiOS/Android本项目为服务端SDK
- **微信开放平台**`weixin-java-open`)主要用于第三方平台,代公众号或小程序进行开发和管理
---------------------------------
### 版本说明
@@ -113,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>

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.

View File

@@ -0,0 +1,129 @@
# 微信支付新版商户转账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
## 快速开始
### 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进行商户转账操作

View File

@@ -0,0 +1,148 @@
# 微信支付新版商户转账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`
- **特点**: 单笔转账,支持更丰富的转账场景
## 使用新版转账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
docs/QUARKUS_SUPPORT.md Normal file
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

0
others/mvnw vendored Normal file → Executable file
View File

68
pom.xml
View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.4.B</version>
<version>4.7.9.B</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>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.4.B</version>
<version>4.7.9.B</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>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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;

View File

@@ -11,6 +11,10 @@ public enum HttpClientType {
* HttpClient
*/
HTTP_CLIENT,
/**
* HttpComponents
*/
HTTP_COMPONENTS
// WxChannelServiceOkHttpImpl 实现经测试无法正常完成业务固暂不支持OK_HTTP方式
// /**
// * OkHttp.

View File

@@ -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);
}
}
```

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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;

View File

@@ -117,6 +117,10 @@ public class WxCpMultiProperties implements Serializable {
* HttpClient
*/
HTTP_CLIENT,
/**
* HttpComponents
*/
HTTP_COMPONENTS,
/**
* OkHttp
*/

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>wx-java-solon-plugins</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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());

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.4.B</version>
<version>4.7.9.B</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>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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());

View File

@@ -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;
/**
* 存储策略
*/

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -48,6 +48,12 @@ public class WxCpProperties {
*/
private String msgAuditLibPath;
/**
* 自定义企业微信服务器baseUrl用于替换默认的 https://qyapi.weixin.qq.com
* 例如http://proxy.company.com:8080
*/
private String baseApiUrl;
/**
* 配置存储策略,默认内存
*/

View File

@@ -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();

View File

@@ -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 ...
}
}
```

View File

@@ -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.7.9.B</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>

View File

@@ -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 {
}

View File

@@ -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 {
}

View File

@@ -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);
}
}
}
}

View File

@@ -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());
}
}

View File

@@ -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();
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.binarywang.spring.starter.wxjava.cp.autoconfigure.WxCpTpMultiAutoConfiguration

View File

@@ -0,0 +1 @@
com.binarywang.spring.starter.wxjava.cp.autoconfigure.WxCpTpMultiAutoConfiguration

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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 {
}

View File

@@ -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) {

View File

@@ -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());
}
}

View File

@@ -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;
}

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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;

View File

@@ -142,6 +142,10 @@ public class WxMpMultiProperties implements Serializable {
* HttpClient
*/
HTTP_CLIENT,
/**
* HttpComponents
*/
HTTP_COMPONENTS,
/**
* OkHttp
*/

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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());

View File

@@ -102,6 +102,21 @@ public class WxMpProperties {
*/
private String httpProxyPassword;
/**
* 连接超时时间,单位毫秒
*/
private int connectionTimeout = 5000;
/**
* 读数据超时时间即socketTimeout单位毫秒
*/
private int soTimeout = 5000;
/**
* 从连接池获取链接的超时时间,单位毫秒
*/
private int connectionRequestTimeout = 5000;
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -28,6 +28,7 @@ public class WxOpenServiceAutoConfiguration {
}
@Bean
@ConditionalOnMissingBean
public WxOpenMessageRouter wxOpenMessageRouter(WxOpenService wxOpenService) {
return new WxOpenMessageRouter(wxOpenService);
}

View File

@@ -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;
}
}

View File

@@ -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 {

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -50,15 +50,18 @@ 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()));
wxPayService.setConfig(payConfig);
return wxPayService;

View File

@@ -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
*/
@@ -90,4 +100,10 @@ public class WxPayProperties {
*/
private boolean useSandboxEnv;
/**
* 自定义API主机地址用于替换默认的 https://api.mch.weixin.qq.com
* 例如http://proxy.company.com:8080
*/
private String apiHostUrl;
}

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>wx-java-spring-boot-starters</artifactId>
<groupId>com.github.binarywang</groupId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -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();

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.4.B</version>
<version>4.7.9.B</version>
</parent>
<artifactId>weixin-graal</artifactId>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.github.binarywang</groupId>
<artifactId>wx-java</artifactId>
<version>4.7.4.B</version>
<version>4.7.9.B</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>

View File

@@ -131,5 +131,5 @@ public interface BaseWxChannelService extends WxService {
*
* @return . request http
*/
RequestHttp getRequestHttp();
RequestHttp<?, ?> getRequestHttp();
}

View File

@@ -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;
}

View File

@@ -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;
/**
* 订单发货
*

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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, "{}");

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -31,9 +31,9 @@ import me.chanjar.weixin.common.util.http.RequestExecutor;
public class WxChannelBasicServiceImpl implements WxChannelBasicService {
/** 微信商店服务 */
private final BaseWxChannelServiceImpl shopService;
private final BaseWxChannelServiceImpl<?, ?> shopService;
public WxChannelBasicServiceImpl(BaseWxChannelServiceImpl shopService) {
public WxChannelBasicServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
this.shopService = shopService;
}
@@ -56,7 +56,7 @@ public class WxChannelBasicServiceImpl implements WxChannelBasicService {
public ChannelImageInfo uploadImg(int respType, File file, int height, int width) throws WxErrorException {
String url = IMG_UPLOAD_URL + "?upload_type=0&resp_type=" + respType + "&height=" + height + "&width=" + width;
RequestExecutor<String, File> executor = ChannelFileUploadRequestExecutor.create(shopService);
String resJson = (String) shopService.execute(executor, url, file);
String resJson = shopService.execute(executor, url, file);
UploadImageResponse response = ResponseUtils.decode(resJson, UploadImageResponse.class);
return response.getImgInfo();
}
@@ -64,19 +64,19 @@ public class WxChannelBasicServiceImpl implements WxChannelBasicService {
@Override
public QualificationFileResponse uploadQualificationFile(File file) throws WxErrorException {
RequestExecutor<String, File> executor = ChannelFileUploadRequestExecutor.create(shopService);
String resJson = (String) shopService.execute(executor, UPLOAD_QUALIFICATION_FILE, file);
String resJson = shopService.execute(executor, UPLOAD_QUALIFICATION_FILE, file);
return ResponseUtils.decode(resJson, QualificationFileResponse.class);
}
@Override
public ChannelImageResponse getImg(String mediaId) throws WxErrorException {
String appId = shopService.getConfig().getAppid();
ChannelImageResponse rs = null;
ChannelImageResponse rs;
try {
String url = GET_IMG_URL + "?media_id=" + mediaId;
RequestExecutor<ChannelImageResponse, String> executor = ChannelMediaDownloadRequestExecutor.create(shopService,
Files.createTempDirectory("wxjava-channel-" + appId).toFile());
rs = (ChannelImageResponse) shopService.execute(executor, url, null);
rs = shopService.execute(executor, url, null);
} catch (IOException e) {
throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e);
}

View File

@@ -33,9 +33,9 @@ import me.chanjar.weixin.common.error.WxErrorException;
public class WxChannelBrandServiceImpl implements WxChannelBrandService {
/** 微信商店服务 */
private final BaseWxChannelServiceImpl shopService;
private final BaseWxChannelServiceImpl<?, ?> shopService;
public WxChannelBrandServiceImpl(BaseWxChannelServiceImpl shopService) {
public WxChannelBrandServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
this.shopService = shopService;
}

View File

@@ -37,9 +37,9 @@ import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
public class WxChannelCategoryServiceImpl implements WxChannelCategoryService {
/** 微信商店服务 */
private final BaseWxChannelServiceImpl shopService;
private final BaseWxChannelServiceImpl<?, ?> shopService;
public WxChannelCategoryServiceImpl(BaseWxChannelServiceImpl shopService) {
public WxChannelCategoryServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
this.shopService = shopService;
}
@@ -56,7 +56,7 @@ public class WxChannelCategoryServiceImpl implements WxChannelCategoryService {
try {
pid = Long.parseLong(parentId);
} catch (Throwable e) {
log.error("parentId必须为数字, " + parentId, e);
log.error("parentId必须为数字, {}", parentId, e);
return Collections.emptyList();
}
String reqJson = "{\"f_cat_id\": " + pid + "}";
@@ -80,7 +80,7 @@ public class WxChannelCategoryServiceImpl implements WxChannelCategoryService {
try {
catId = Long.parseLong(id);
} catch (Throwable e) {
log.error("id必须为数字, " + id, e);
log.error("id必须为数字, {}", id, e);
return ResponseUtils.internalError(CategoryDetailResult.class);
}
String reqJson = "{\"cat_id\": " + catId + "}";

View File

@@ -20,9 +20,9 @@ public class WxChannelCompassFinderServiceImpl implements WxChannelCompassFinder
/**
* 微信商店服务
*/
private final BaseWxChannelServiceImpl shopService;
private final BaseWxChannelServiceImpl<?, ?> shopService;
public WxChannelCompassFinderServiceImpl(BaseWxChannelServiceImpl shopService) {this.shopService = shopService;}
public WxChannelCompassFinderServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {this.shopService = shopService;}
@Override
public OverallResponse getOverall(String ds) throws WxErrorException {

View File

@@ -41,9 +41,9 @@ public class WxChannelCompassShopServiceImpl implements WxChannelCompassShopServ
/**
* 微信商店服务
*/
private final BaseWxChannelServiceImpl shopService;
private final BaseWxChannelServiceImpl<?, ?> shopService;
public WxChannelCompassShopServiceImpl(BaseWxChannelServiceImpl shopService) {this.shopService = shopService;}
public WxChannelCompassShopServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {this.shopService = shopService;}
@Override
public ShopOverallResponse getShopOverall(String ds) throws WxErrorException {

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