mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
Compare commits
152 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd3bbde725 | ||
|
|
84e70febdf | ||
|
|
155f3f778f | ||
|
|
26f5887e22 | ||
|
|
23a2e18f1c | ||
|
|
8f20f3baba | ||
|
|
93a2fa701a | ||
|
|
1f4ed68750 | ||
|
|
c4f383462e | ||
|
|
03114b9900 | ||
|
|
f6d9e8ba4d | ||
|
|
1da6cf56ff | ||
|
|
e655a33956 | ||
|
|
9940546956 | ||
|
|
1bd50d4d2f | ||
|
|
8e46da5003 | ||
|
|
b1e7cd2cd7 | ||
|
|
7fcd1ed5b3 | ||
|
|
21d5f2fdd2 | ||
|
|
e57b7e1eb5 | ||
|
|
833f60c68d | ||
|
|
1922aaaa94 | ||
|
|
3c440eacb3 | ||
|
|
b8d2bb345a | ||
|
|
730ac24c3f | ||
|
|
ebb9ccdebe | ||
|
|
76c7e994a5 | ||
|
|
092e992817 | ||
|
|
69a2ab9cc7 | ||
|
|
0854e4d971 | ||
|
|
57e12dee29 | ||
|
|
4d4294707b | ||
|
|
9ab64167d5 | ||
|
|
28fac4ec2e | ||
|
|
b94106fd57 | ||
|
|
d4186c49c1 | ||
|
|
bb573afcaf | ||
|
|
e9bc5d0109 | ||
|
|
738bcf7755 | ||
|
|
de4848b2f7 | ||
|
|
b26c786797 | ||
|
|
b9b4f00438 | ||
|
|
98329b11da | ||
|
|
db85c0ab8a | ||
|
|
ca567ce310 | ||
|
|
a6825a62bb | ||
|
|
9fd12b2a09 | ||
|
|
10f71234e4 | ||
|
|
9aa2781e68 | ||
|
|
cfe1f6dc95 | ||
|
|
c0edd9fd16 | ||
|
|
1788d9071e | ||
|
|
e6a844ab70 | ||
|
|
6fc17201e1 | ||
|
|
ad19f653c7 | ||
|
|
7018dceb1c | ||
|
|
399f3648c0 | ||
|
|
88bdd4a36e | ||
|
|
213cf6fd67 | ||
|
|
c8d84da2ab | ||
|
|
118839a49d | ||
|
|
8447caa75f | ||
|
|
1eefd11e03 | ||
|
|
781798345e | ||
|
|
0424d75882 | ||
|
|
e61ad44d27 | ||
|
|
dc46d9de75 | ||
|
|
bc6fb7b58e | ||
|
|
983e4f1e66 | ||
|
|
7ffc1b3719 | ||
|
|
8bb4a21598 | ||
|
|
a881de59a5 | ||
|
|
14f8c8ebc2 | ||
|
|
875c35e745 | ||
|
|
262a02b606 | ||
|
|
3a1d8075fc | ||
|
|
2e952c76c8 | ||
|
|
e5ef34553d | ||
|
|
4cdd056a3e | ||
|
|
57a6ef1179 | ||
|
|
4754a562ca | ||
|
|
62f89987c0 | ||
|
|
990dbba06b | ||
|
|
d85e04a72a | ||
|
|
aacfa947be | ||
|
|
3e4ee57e1c | ||
|
|
d4cf48d059 | ||
|
|
696ce8621e | ||
|
|
8c8139533d | ||
|
|
84c69d4900 | ||
|
|
d52e225626 | ||
|
|
686dff6436 | ||
|
|
92431aabd9 | ||
|
|
29bc950f92 | ||
|
|
5c74c1d930 | ||
|
|
52d0b2fc1c | ||
|
|
5b816242a4 | ||
|
|
a45f0ac048 | ||
|
|
4731479b93 | ||
|
|
cc344f105e | ||
|
|
172b96444f | ||
|
|
b3b8c273c7 | ||
|
|
b6d489e9c8 | ||
|
|
72266c3aeb | ||
|
|
ccbfa98864 | ||
|
|
bf35797b91 | ||
|
|
41081561b5 | ||
|
|
8878f06c1e | ||
|
|
22d288f6cd | ||
|
|
b0af2c704e | ||
|
|
320f05e6d6 | ||
|
|
4d7fd68fe5 | ||
|
|
388188b694 | ||
|
|
ecce9292b2 | ||
|
|
96a5cc995b | ||
|
|
4d66dd09ca | ||
|
|
08e2107667 | ||
|
|
f71ac2185c | ||
|
|
5bde717f8f | ||
|
|
8bacc9425e | ||
|
|
3e1a38a696 | ||
|
|
fefe737803 | ||
|
|
d0b7a526f6 | ||
|
|
47051bdf31 | ||
|
|
f5dd32de86 | ||
|
|
d776792bae | ||
|
|
1a74e3e3a8 | ||
|
|
2762a98279 | ||
|
|
04c162f03a | ||
|
|
5c2a36c538 | ||
|
|
2c4b5ea128 | ||
|
|
9a6db34b6a | ||
|
|
77b90626f3 | ||
|
|
063fbb7f19 | ||
|
|
a7b007f853 | ||
|
|
c91a5a8e22 | ||
|
|
a051587d3e | ||
|
|
245cf72104 | ||
|
|
fb57af7409 | ||
|
|
88a5bc4f43 | ||
|
|
dc674ce024 | ||
|
|
854b50bd51 | ||
|
|
2d8d1df00e | ||
|
|
2279105fef | ||
|
|
cbb3b24577 | ||
|
|
ddfbee25e1 | ||
|
|
6a4ed91ae2 | ||
|
|
59f5a99fda | ||
|
|
3718b499a0 | ||
|
|
bb76db052d | ||
|
|
e16e0e9373 | ||
|
|
89280abd00 |
13
.github/agents/my-agent.agent.md
vendored
Normal file
13
.github/agents/my-agent.agent.md
vendored
Normal 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
202
.github/copilot-instructions.md
vendored
Normal 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
4
.github/workflows
vendored
@@ -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
94
.github/workflows/maven-publish.yml
vendored
Normal 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
142
README.md
@@ -1,77 +1,77 @@
|
||||
## WxJava - 微信开发 Java SDK
|
||||
[](https://github.com/binarywang/WxJava)
|
||||
[](https://gitee.com/binary/weixin-java-tools)
|
||||
[](https://gitcode.com/binary/WxJava)
|
||||
|
||||
[](https://gitee.com/binary/weixin-java-tools)
|
||||
[](https://github.com/binarywang/WxJava)
|
||||
[](https://github.com/binarywang/WxJava/releases)
|
||||
[](http://mvnrepository.com/artifact/com.github.binarywang/wx-java)
|
||||
[](https://circleci.com/gh/binarywang/WxJava/tree/develop)
|
||||
[](https://github.com/binarywang/WxJava/releases)
|
||||
[](https://central.sonatype.com/artifact/com.github.binarywang/wx-java/versions)
|
||||
[](https://circleci.com/gh/binarywang/WxJava/tree/develop)
|
||||
[](https://www.jetbrains.com/?from=WxJava-weixin-java-tools)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
#### 微信`Java`开发工具包,支持包括微信支付、开放平台、公众号、企业微信、视频号、小程序等微信功能模块的后端开发。
|
||||
<div align="center">
|
||||
<a href="https://hellogithub.com/repository/6de6147050c94db4aedfd7098d19f8d8" target="_blank">
|
||||
<img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=6de6147050c94db4aedfd7098d19f8d8&claim_uid=mwKh0tILBfjlezR" alt="Featured|HelloGitHub" width="250" height="54" />
|
||||
</a>
|
||||
<a href="https://trendshift.io/repositories/12152" target="_blank">
|
||||
<img src="https://trendshift.io/api/badge/repositories/12152" alt="binarywang%2FWxJava | 趋势转变" width="250" height="55" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### 微信`Java`开发工具包,支持包括微信支付、开放平台、公众号、企业微信、视频号、小程序等微信功能模块的后端开发。
|
||||
<div align="center">
|
||||
<b>特别赞助</b>
|
||||
<table cellspacing="0" cellpadding="0" width="500">
|
||||
<tr>
|
||||
<td align="center" colspan="3">
|
||||
<a href="http://www.ccflow.org/?from=wxjava" target="_blank">
|
||||
<img height="120" src="https://ccfast.cc/AD/ccflow2.png" alt="ccflow">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" colspan="2">
|
||||
<a href="https://www.jeequan.com/product/jeepay.html" target="_blank">
|
||||
<img height="120" src="https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/wxjava_jeepay.png" alt="计全支付Jeepay,开源支付系统">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.mall4j.com/cn/?statId=9" target="_blank">
|
||||
<img height="120" src="https://img.mall4j.com/mall.png" alt="Mall4j">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="http://mp.weixin.qq.com/mp/homepage?__biz=MzI3MzAwMzk4OA==&hid=1&sn=f31af3bf562b116b061c9ab4edf70b61&scene=18#wechat_redirect" target="_blank">
|
||||
<img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/develop/images/qrcodes/mp.png" alt="mp qrcode">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.diboot.com?from=wxjava" target="_blank">
|
||||
<img height="120" src="https://www.diboot.com/img/diboot_ad.png" alt="diboot低代码开发平台">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://www.crmeb.com/xiazai" target="_blank">
|
||||
<img height="120" src="https://crmebjavamer.oss-cn-beijing.aliyuncs.com/crmebimage/gitee/WechatIMG202.jpg" alt="ad">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<table align="center" cellspacing="0" cellpadding="0" width="500">
|
||||
<tr>
|
||||
<td align="center" valign="middle" colspan="3">
|
||||
<a href="http://www.ccflow.org/?from=wxjava" target="_blank">
|
||||
<img height="120" src="https://ccfast.cc/AD/ccflow2.png" alt="ccflow">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle" colspan="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="Featured|HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" />
|
||||
</a>
|
||||
<a href="https://trendshift.io/repositories/12152" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12152" alt="binarywang%2FWxJava | 趋势转变" style="width: 250px; height: 55px;" width="250" height="55"/>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### 重要信息
|
||||
1. [`WxJava` 荣获 `GitCode` 2024年度十大开源社区奖项](https://mp.weixin.qq.com/s/wM_UlMsDm3IZ1CPPDvcvQw)。
|
||||
2. 项目合作洽谈请联系微信`binary0000`(在微信里自行搜索并添加好友,请注明来意,如有关于SDK问题需讨论请参考下文入群讨论,不要加此微信)。
|
||||
3. **2024-12-30 发布 [【4.7.0正式版】](https://mp.weixin.qq.com/s/_7k-XLYBqeJJhvHWCsdT0A)**!
|
||||
4. 贡献源码可以参考视频:[【贡献源码全过程(上集)】](https://mp.weixin.qq.com/s/3xUZSATWwHR_gZZm207h7Q)、[【贡献源码全过程(下集)】](https://mp.weixin.qq.com/s/nyzJwVVoYSJ4hSbwyvTx9A) ,友情提供:[程序员小山与Bug](https://space.bilibili.com/473631007)
|
||||
5. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用 `maven` 或 `gradle` 引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;
|
||||
6. 微信开发新手请务必阅读【开发文档】([Gitee Wiki](https://gitee.com/binary/weixin-java-tools/wikis/Home) 或者 [Github Wiki](https://github.com/binarywang/WxJava/wiki))的常见问题部分,可以少走很多弯路,节省不少时间。
|
||||
7. 技术交流群:想获得QQ群/微信群/钉钉企业群等信息的同学,请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式,同时也可以在微信中搜索 `weixin-java-tools` 或 `WxJava` 后选择正确的公众号进行关注,该公众号会及时通知SDK相关更新信息,并不定期分享微信Java开发相关技术知识;
|
||||
8. 钉钉技术交流群:`32206329`(技术交流2群), `30294972`(技术交流1群,目前已满),`35724728`(通知群,实时通知Github项目变更记录)。
|
||||
9. 微信开发新手或者Java开发新手在群内提问或新开Issue提问前,请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md),并确保已查阅过 [【开发文档Wiki】](https://github.com/binarywang/WxJava/wiki) ,避免浪费大家的宝贵时间;
|
||||
10. 寻求帮助时需贴代码或大长串异常信息的,请利用 http://paste.ubuntu.com
|
||||
5. 贡献源码可以参考视频:[【贡献源码全过程(上集)】](https://mp.weixin.qq.com/s/3xUZSATWwHR_gZZm207h7Q)、[【贡献源码全过程(下集)】](https://mp.weixin.qq.com/s/nyzJwVVoYSJ4hSbwyvTx9A) ,友情提供:[程序员小山与Bug](https://space.bilibili.com/473631007)
|
||||
6. 新手重要提示:本项目仅是一个SDK开发工具包,未提供Web实现,建议使用 `maven` 或 `gradle` 引用本项目即可使用本SDK提供的各种功能,详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码;
|
||||
7. 微信开发新手请务必阅读【开发文档】([Gitee Wiki](https://gitee.com/binary/weixin-java-tools/wikis/Home) 或者 [Github Wiki](https://github.com/binarywang/WxJava/wiki))的常见问题部分,可以少走很多弯路,节省不少时间。
|
||||
8. 技术交流群:想获得QQ群/微信群/钉钉企业群等信息的同学,请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式,同时也可以在微信中搜索 `weixin-java-tools` 或 `WxJava` 后选择正确的公众号进行关注,该公众号会及时通知SDK相关更新信息,并不定期分享微信Java开发相关技术知识;
|
||||
9. 钉钉技术交流群:`32206329`(技术交流2群), `30294972`(技术交流1群,目前已满),`35724728`(通知群,实时通知Github项目变更记录)。
|
||||
10. 微信开发新手或者Java开发新手在群内提问或新开Issue提问前,请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md),并确保已查阅过 [【开发文档Wiki】](https://github.com/binarywang/WxJava/wiki) ,避免浪费大家的宝贵时间;
|
||||
11. 寻求帮助时需贴代码或大长串异常信息的,请利用 http://paste.ubuntu.com
|
||||
|
||||
--------------------------------
|
||||
### 其他说明
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
---------------------------------
|
||||
### Maven 引用方式
|
||||
注意:最新版本(包括测试版)为 [](http://mvnrepository.com/artifact/com.github.binarywang/wx-java),以下为最新正式版。
|
||||
注意:最新版本(包括测试版)为 [](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` 模块
|
||||
- 客户端集成:需使用微信官方提供的移动端SDK(iOS/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. 目前最新版本号为 [](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. 目前最新版本号为 [](http://mvnrepository.com/artifact/com.github.binarywang/wx-java) ,也可以通过访问以下链接分别查看各个模块最新的版本:
|
||||
[【微信支付】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-pay/versions) 、[【小程序】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-miniapp/versions) 、[【公众号】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-mp/versions) 、[【企业微信】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-cp/versions)、[【开放平台】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-open/versions)、[【视频号】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-channel/versions)
|
||||
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
80
docs/MINIAPP_KEFU_SERVICE.md
Normal file
80
docs/MINIAPP_KEFU_SERVICE.md
Normal 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.
|
||||
129
docs/NEW_TRANSFER_API_SUPPORT.md
Normal file
129
docs/NEW_TRANSFER_API_SUPPORT.md
Normal 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进行商户转账操作!
|
||||
148
docs/NEW_TRANSFER_API_USAGE.md
Normal file
148
docs/NEW_TRANSFER_API_USAGE.md
Normal 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
112
docs/QUARKUS_SUPPORT.md
Normal 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
0
others/mvnw
vendored
Normal file → Executable file
68
pom.xml
68
pom.xml
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.binarywang.solon.wxjava.channel.service.WxChannelMultiServicesImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.channel.api.WxChannelService;
|
||||
import me.chanjar.weixin.channel.api.impl.WxChannelServiceHttpComponentsImpl;
|
||||
import me.chanjar.weixin.channel.api.impl.WxChannelServiceHttpClientImpl;
|
||||
import me.chanjar.weixin.channel.api.impl.WxChannelServiceImpl;
|
||||
import me.chanjar.weixin.channel.config.WxChannelConfig;
|
||||
@@ -84,6 +85,9 @@ public abstract class AbstractWxChannelConfiguration {
|
||||
case HTTP_CLIENT:
|
||||
wxChannelService = new WxChannelServiceHttpClientImpl();
|
||||
break;
|
||||
case HTTP_COMPONENTS:
|
||||
wxChannelService = new WxChannelServiceHttpComponentsImpl();
|
||||
break;
|
||||
default:
|
||||
wxChannelService = new WxChannelServiceImpl();
|
||||
break;
|
||||
|
||||
@@ -11,6 +11,10 @@ public enum HttpClientType {
|
||||
* HttpClient
|
||||
*/
|
||||
HTTP_CLIENT,
|
||||
/**
|
||||
* HttpComponents
|
||||
*/
|
||||
HTTP_COMPONENTS
|
||||
// WxChannelServiceOkHttpImpl 实现经测试无法正常完成业务固暂不支持OK_HTTP方式
|
||||
// /**
|
||||
// * OkHttp.
|
||||
|
||||
92
solon-plugins/wx-java-channel-solon-plugin/README.md
Normal file
92
solon-plugins/wx-java-channel-solon-plugin/README.md
Normal 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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@ import com.binarywang.solon.wxjava.cp_multi.service.WxCpMultiServicesImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.api.impl.WxCpServiceApacheHttpClientImpl;
|
||||
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
|
||||
import me.chanjar.weixin.cp.api.impl.WxCpServiceJoddHttpImpl;
|
||||
import me.chanjar.weixin.cp.api.impl.WxCpServiceOkHttpImpl;
|
||||
import me.chanjar.weixin.cp.api.impl.*;
|
||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -96,6 +93,9 @@ public abstract class AbstractWxCpConfiguration {
|
||||
case HTTP_CLIENT:
|
||||
wxCpService = new WxCpServiceApacheHttpClientImpl();
|
||||
break;
|
||||
case HTTP_COMPONENTS:
|
||||
wxCpService = new WxCpServiceHttpComponentsImpl();
|
||||
break;
|
||||
default:
|
||||
wxCpService = new WxCpServiceImpl();
|
||||
break;
|
||||
|
||||
@@ -117,6 +117,10 @@ public class WxCpMultiProperties implements Serializable {
|
||||
* HttpClient
|
||||
*/
|
||||
HTTP_CLIENT,
|
||||
/**
|
||||
* HttpComponents
|
||||
*/
|
||||
HTTP_COMPONENTS,
|
||||
/**
|
||||
* OkHttp
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -119,6 +119,8 @@ public abstract class AbstractWxChannelConfiguration {
|
||||
config.setAesKey(aesKey);
|
||||
}
|
||||
config.setStableAccessToken(useStableAccessToken);
|
||||
config.setApiHostUrl(StringUtils.trimToNull(wxChannelSingleProperties.getApiHostUrl()));
|
||||
config.setAccessTokenUrl(StringUtils.trimToNull(wxChannelSingleProperties.getAccessTokenUrl()));
|
||||
}
|
||||
|
||||
private void configHttp(WxChannelDefaultConfigImpl config, WxChannelMultiProperties.ConfigStorage storage) {
|
||||
|
||||
@@ -40,4 +40,16 @@ public class WxChannelSingleProperties implements Serializable {
|
||||
* 是否使用稳定版 Access Token
|
||||
*/
|
||||
private boolean useStableAccessToken = false;
|
||||
|
||||
/**
|
||||
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
|
||||
* 例如:http://proxy.company.com:8080
|
||||
*/
|
||||
private String apiHostUrl;
|
||||
|
||||
/**
|
||||
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
|
||||
* 例如:http://proxy.company.com:8080/oauth/token
|
||||
*/
|
||||
private String accessTokenUrl;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java-channel-multi-spring-boot-starter</artifactId>
|
||||
<artifactId>wx-java-channel-spring-boot-starter</artifactId>
|
||||
<version>${version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ public abstract class AbstractWxChannelConfigStorageConfiguration {
|
||||
config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
|
||||
config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
|
||||
config.setStableAccessToken(properties.isUseStableAccessToken());
|
||||
config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
|
||||
config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
|
||||
|
||||
WxChannelProperties.ConfigStorage configStorageProperties = properties.getConfigStorage();
|
||||
config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
|
||||
|
||||
@@ -46,6 +46,18 @@ public class WxChannelProperties {
|
||||
*/
|
||||
private boolean useStableAccessToken = false;
|
||||
|
||||
/**
|
||||
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
|
||||
* 例如:http://proxy.company.com:8080
|
||||
*/
|
||||
private String apiHostUrl;
|
||||
|
||||
/**
|
||||
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
|
||||
* 例如:http://proxy.company.com:8080/oauth/token
|
||||
*/
|
||||
private String accessTokenUrl;
|
||||
|
||||
/**
|
||||
* 存储策略
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -139,6 +139,9 @@ public abstract class AbstractWxCpConfiguration {
|
||||
if (StringUtils.isNotBlank(msgAuditLibPath)) {
|
||||
config.setMsgAuditLibPath(msgAuditLibPath);
|
||||
}
|
||||
if (StringUtils.isNotBlank(wxCpSingleProperties.getBaseApiUrl())) {
|
||||
config.setBaseApiUrl(wxCpSingleProperties.getBaseApiUrl());
|
||||
}
|
||||
}
|
||||
|
||||
private void configHttp(WxCpDefaultConfigImpl config, WxCpMultiProperties.ConfigStorage storage) {
|
||||
|
||||
@@ -43,4 +43,10 @@ public class WxCpSingleProperties implements Serializable {
|
||||
* 微信企业号应用 会话存档类库路径
|
||||
*/
|
||||
private String msgAuditLibPath;
|
||||
|
||||
/**
|
||||
* 自定义企业微信服务器baseUrl,用于替换默认的 https://qyapi.weixin.qq.com
|
||||
* 例如:http://proxy.company.com:8080
|
||||
*/
|
||||
private String baseApiUrl;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -48,6 +48,12 @@ public class WxCpProperties {
|
||||
*/
|
||||
private String msgAuditLibPath;
|
||||
|
||||
/**
|
||||
* 自定义企业微信服务器baseUrl,用于替换默认的 https://qyapi.weixin.qq.com
|
||||
* 例如:http://proxy.company.com:8080
|
||||
*/
|
||||
private String baseApiUrl;
|
||||
|
||||
/**
|
||||
* 配置存储策略,默认内存
|
||||
*/
|
||||
|
||||
@@ -37,6 +37,9 @@ public abstract class AbstractWxCpConfigStorageConfiguration {
|
||||
if (StringUtils.isNotBlank(msgAuditLibPath)) {
|
||||
config.setMsgAuditLibPath(msgAuditLibPath);
|
||||
}
|
||||
if (StringUtils.isNotBlank(properties.getBaseApiUrl())) {
|
||||
config.setBaseApiUrl(properties.getBaseApiUrl());
|
||||
}
|
||||
|
||||
WxCpProperties.ConfigStorage storage = properties.getConfigStorage();
|
||||
String httpProxyHost = storage.getHttpProxyHost();
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# wx-java-cp-multi-spring-boot-starter
|
||||
|
||||
企业微信多账号配置
|
||||
|
||||
- 实现多 WxCpService 初始化。
|
||||
- 未实现 WxCpTpService 初始化,需要的小伙伴可以参考多 WxCpService 配置的实现。
|
||||
- 未实现 WxCpCgService 初始化,需要的小伙伴可以参考多 WxCpService 配置的实现。
|
||||
|
||||
## 快速开始
|
||||
|
||||
1. 引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java-cp-multi-spring-boot-starter</artifactId>
|
||||
<version>${version}</version>
|
||||
</dependency>
|
||||
```
|
||||
2. 添加配置(application.properties)
|
||||
```properties
|
||||
# 应用 1 配置
|
||||
wx.cp.corps.tenantId1.corp-id = @corp-id
|
||||
wx.cp.corps.tenantId1.corp-secret = @corp-secret
|
||||
## 选填
|
||||
wx.cp.corps.tenantId1.agent-id = @agent-id
|
||||
wx.cp.corps.tenantId1.token = @token
|
||||
wx.cp.corps.tenantId1.aes-key = @aes-key
|
||||
wx.cp.corps.tenantId1.msg-audit-priKey = @msg-audit-priKey
|
||||
wx.cp.corps.tenantId1.msg-audit-lib-path = @msg-audit-lib-path
|
||||
|
||||
# 应用 2 配置
|
||||
wx.cp.corps.tenantId2.corp-id = @corp-id
|
||||
wx.cp.corps.tenantId2.corp-secret = @corp-secret
|
||||
## 选填
|
||||
wx.cp.corps.tenantId2.agent-id = @agent-id
|
||||
wx.cp.corps.tenantId2.token = @token
|
||||
wx.cp.corps.tenantId2.aes-key = @aes-key
|
||||
wx.cp.corps.tenantId2.msg-audit-priKey = @msg-audit-priKey
|
||||
wx.cp.corps.tenantId2.msg-audit-lib-path = @msg-audit-lib-path
|
||||
|
||||
# 公共配置
|
||||
## ConfigStorage 配置(选填)
|
||||
wx.cp.config-storage.type=memory # 配置类型: memory(默认), jedis, redisson, redistemplate
|
||||
## http 客户端配置(选填)
|
||||
## # http客户端类型: http_client(默认), ok_http, jodd_http
|
||||
wx.cp.config-storage.http-client-type=http_client
|
||||
wx.cp.config-storage.http-proxy-host=
|
||||
wx.cp.config-storage.http-proxy-port=
|
||||
wx.cp.config-storage.http-proxy-username=
|
||||
wx.cp.config-storage.http-proxy-password=
|
||||
## 最大重试次数,默认:5 次,如果小于 0,则为 0
|
||||
wx.cp.config-storage.max-retry-times=5
|
||||
## 重试时间间隔步进,默认:1000 毫秒,如果小于 0,则为 1000
|
||||
wx.cp.config-storage.retry-sleep-millis=1000
|
||||
```
|
||||
3. 支持自动注入的类型: `WxCpMultiServices`
|
||||
|
||||
4. 使用样例
|
||||
|
||||
```java
|
||||
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.api.WxCpUserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class DemoService {
|
||||
@Autowired
|
||||
private WxCpTpMultiServices wxCpTpMultiServices;
|
||||
|
||||
public void test() {
|
||||
// 应用 1 的 WxCpService
|
||||
WxCpService wxCpService1 = wxCpMultiServices.getWxCpService("tenantId1");
|
||||
WxCpUserService userService1 = wxCpService1.getUserService();
|
||||
userService1.getUserId("xxx");
|
||||
// todo ...
|
||||
|
||||
// 应用 2 的 WxCpService
|
||||
WxCpService wxCpService2 = wxCpMultiServices.getWxCpService("tenantId2");
|
||||
WxCpUserService userService2 = wxCpService2.getUserService();
|
||||
userService2.getUserId("xxx");
|
||||
// todo ...
|
||||
|
||||
// 应用 3 的 WxCpService
|
||||
WxCpService wxCpService3 = wxCpMultiServices.getWxCpService("tenantId3");
|
||||
// 判断是否为空
|
||||
if (wxCpService3 == null) {
|
||||
// todo wxCpService3 为空,请先配置 tenantId3 企业微信应用参数
|
||||
return;
|
||||
}
|
||||
WxCpUserService userService3 = wxCpService3.getUserService();
|
||||
userService3.getUserId("xxx");
|
||||
// todo ...
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.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>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.autoconfigure;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.cp.configuration.WxCpTpMultiServicesAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* 企业微信自动注册
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Configuration
|
||||
@Import(WxCpTpMultiServicesAutoConfiguration.class)
|
||||
public class WxCpTpMultiAutoConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.configuration;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInJedisTpConfiguration;
|
||||
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInMemoryTpConfiguration;
|
||||
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInRedisTemplateTpConfiguration;
|
||||
import com.binarywang.spring.starter.wxjava.cp.configuration.services.WxCpTpInRedissonTpConfiguration;
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* 企业微信平台相关服务自动注册
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxCpTpMultiProperties.class)
|
||||
@Import({
|
||||
WxCpTpInJedisTpConfiguration.class,
|
||||
WxCpTpInMemoryTpConfiguration.class,
|
||||
WxCpTpInRedissonTpConfiguration.class,
|
||||
WxCpTpInRedisTemplateTpConfiguration.class
|
||||
})
|
||||
public class WxCpTpMultiServicesAutoConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpSingleProperties;
|
||||
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
|
||||
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServicesImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
|
||||
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceApacheHttpClientImpl;
|
||||
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceImpl;
|
||||
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceJoddHttpImpl;
|
||||
import me.chanjar.weixin.cp.tp.service.impl.WxCpTpServiceOkHttpImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* WxCpConfigStorage 抽象配置类
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public abstract class AbstractWxCpTpConfiguration {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param wxCpTpMultiProperties 应用列表配置
|
||||
* @param services 用于支持,应用启动之后,可以调用这个接口添加新服务对象。主要是配置是从数据库中读取的
|
||||
* @return
|
||||
*/
|
||||
public WxCpTpMultiServices wxCpMultiServices(WxCpTpMultiProperties wxCpTpMultiProperties,WxCpTpMultiServices services) {
|
||||
Map<String, WxCpTpSingleProperties> corps = wxCpTpMultiProperties.getCorps();
|
||||
if (corps == null || corps.isEmpty()) {
|
||||
log.warn("企业微信应用参数未配置,通过 WxCpMultiServices#getWxCpTpService(\"tenantId\")获取实例将返回空");
|
||||
return new WxCpTpMultiServicesImpl();
|
||||
}
|
||||
|
||||
if (services == null) {
|
||||
services = new WxCpTpMultiServicesImpl();
|
||||
}
|
||||
|
||||
Set<Map.Entry<String, WxCpTpSingleProperties>> entries = corps.entrySet();
|
||||
for (Map.Entry<String, WxCpTpSingleProperties> entry : entries) {
|
||||
String tenantId = entry.getKey();
|
||||
WxCpTpSingleProperties wxCpTpSingleProperties = entry.getValue();
|
||||
WxCpTpDefaultConfigImpl storage = this.wxCpTpConfigStorage(wxCpTpMultiProperties);
|
||||
this.configCorp(storage, wxCpTpSingleProperties);
|
||||
this.configHttp(storage, wxCpTpMultiProperties.getConfigStorage());
|
||||
WxCpTpService wxCpTpService = this.wxCpTpService(storage, wxCpTpMultiProperties.getConfigStorage());
|
||||
if (services.getWxCpTpService(tenantId) == null) {
|
||||
// 不存在的才会添加到服务列表中
|
||||
services.addWxCpTpService(tenantId, wxCpTpService);
|
||||
}
|
||||
}
|
||||
return services;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置 WxCpDefaultConfigImpl
|
||||
*
|
||||
* @param wxCpTpMultiProperties 参数
|
||||
* @return WxCpDefaultConfigImpl
|
||||
*/
|
||||
protected abstract WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties);
|
||||
|
||||
private WxCpTpService wxCpTpService(WxCpTpConfigStorage wxCpTpConfigStorage, WxCpTpMultiProperties.ConfigStorage storage) {
|
||||
WxCpTpMultiProperties.HttpClientType httpClientType = storage.getHttpClientType();
|
||||
WxCpTpService cpTpService;
|
||||
switch (httpClientType) {
|
||||
case OK_HTTP:
|
||||
cpTpService = new WxCpTpServiceOkHttpImpl();
|
||||
break;
|
||||
case JODD_HTTP:
|
||||
cpTpService = new WxCpTpServiceJoddHttpImpl();
|
||||
break;
|
||||
case HTTP_CLIENT:
|
||||
cpTpService = new WxCpTpServiceApacheHttpClientImpl();
|
||||
break;
|
||||
default:
|
||||
cpTpService = new WxCpTpServiceImpl();
|
||||
break;
|
||||
}
|
||||
cpTpService.setWxCpTpConfigStorage(wxCpTpConfigStorage);
|
||||
int maxRetryTimes = storage.getMaxRetryTimes();
|
||||
if (maxRetryTimes < 0) {
|
||||
maxRetryTimes = 0;
|
||||
}
|
||||
int retrySleepMillis = storage.getRetrySleepMillis();
|
||||
if (retrySleepMillis < 0) {
|
||||
retrySleepMillis = 1000;
|
||||
}
|
||||
cpTpService.setRetrySleepMillis(retrySleepMillis);
|
||||
cpTpService.setMaxRetryTimes(maxRetryTimes);
|
||||
return cpTpService;
|
||||
}
|
||||
|
||||
private void configCorp(WxCpTpDefaultConfigImpl config, WxCpTpSingleProperties wxCpTpSingleProperties) {
|
||||
String corpId = wxCpTpSingleProperties.getCorpId();
|
||||
String providerSecret = wxCpTpSingleProperties.getProviderSecret();
|
||||
String suiteId = wxCpTpSingleProperties.getSuiteId();
|
||||
String token = wxCpTpSingleProperties.getToken();
|
||||
String suiteSecret = wxCpTpSingleProperties.getSuiteSecret();
|
||||
// 企业微信,私钥,会话存档路径
|
||||
config.setCorpId(corpId);
|
||||
config.setProviderSecret(providerSecret);
|
||||
config.setEncodingAESKey(wxCpTpSingleProperties.getEncodingAESKey());
|
||||
config.setSuiteId(suiteId);
|
||||
config.setToken(token);
|
||||
config.setSuiteSecret(suiteSecret);
|
||||
}
|
||||
|
||||
private void configHttp(WxCpTpDefaultConfigImpl config, WxCpTpMultiProperties.ConfigStorage storage) {
|
||||
String httpProxyHost = storage.getHttpProxyHost();
|
||||
Integer httpProxyPort = storage.getHttpProxyPort();
|
||||
String httpProxyUsername = storage.getHttpProxyUsername();
|
||||
String httpProxyPassword = storage.getHttpProxyPassword();
|
||||
if (StringUtils.isNotBlank(httpProxyHost)) {
|
||||
config.setHttpProxyHost(httpProxyHost);
|
||||
if (httpProxyPort != null) {
|
||||
config.setHttpProxyPort(httpProxyPort);
|
||||
}
|
||||
if (StringUtils.isNotBlank(httpProxyUsername)) {
|
||||
config.setHttpProxyUsername(httpProxyUsername);
|
||||
}
|
||||
if (StringUtils.isNotBlank(httpProxyPassword)) {
|
||||
config.setHttpProxyPassword(httpProxyPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiRedisProperties;
|
||||
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpJedisConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpTpJedisConfigImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
/**
|
||||
* 自动装配基于 jedis 策略配置
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
prefix = WxCpTpMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "jedis"
|
||||
)
|
||||
@RequiredArgsConstructor
|
||||
public class WxCpTpInJedisTpConfiguration extends AbstractWxCpTpConfiguration {
|
||||
private final WxCpTpMultiProperties wxCpTpMultiProperties;
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
@Bean
|
||||
public WxCpTpMultiServices wxCpMultiServices() {
|
||||
return this.wxCpMultiServices(wxCpTpMultiProperties,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
return this.configRedis(wxCpTpMultiProperties);
|
||||
}
|
||||
|
||||
private WxCpTpDefaultConfigImpl configRedis(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
WxCpTpMultiRedisProperties wxCpTpMultiRedisProperties = wxCpTpMultiProperties.getConfigStorage().getRedis();
|
||||
JedisPool jedisPool;
|
||||
if (wxCpTpMultiRedisProperties != null && StringUtils.isNotEmpty(wxCpTpMultiRedisProperties.getHost())) {
|
||||
jedisPool = getJedisPool(wxCpTpMultiProperties);
|
||||
} else {
|
||||
jedisPool = applicationContext.getBean(JedisPool.class);
|
||||
}
|
||||
return new WxCpTpJedisConfigImpl(jedisPool, wxCpTpMultiProperties.getConfigStorage().getKeyPrefix());
|
||||
}
|
||||
|
||||
private JedisPool getJedisPool(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
WxCpTpMultiProperties.ConfigStorage storage = wxCpTpMultiProperties.getConfigStorage();
|
||||
WxCpTpMultiRedisProperties redis = storage.getRedis();
|
||||
|
||||
JedisPoolConfig config = new JedisPoolConfig();
|
||||
if (redis.getMaxActive() != null) {
|
||||
config.setMaxTotal(redis.getMaxActive());
|
||||
}
|
||||
if (redis.getMaxIdle() != null) {
|
||||
config.setMaxIdle(redis.getMaxIdle());
|
||||
}
|
||||
if (redis.getMaxWaitMillis() != null) {
|
||||
config.setMaxWaitMillis(redis.getMaxWaitMillis());
|
||||
}
|
||||
if (redis.getMinIdle() != null) {
|
||||
config.setMinIdle(redis.getMinIdle());
|
||||
}
|
||||
config.setTestOnBorrow(true);
|
||||
config.setTestWhileIdle(true);
|
||||
|
||||
return new JedisPool(config, redis.getHost(), redis.getPort(),
|
||||
redis.getTimeout(), redis.getPassword(), redis.getDatabase());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
|
||||
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 自动装配基于内存策略配置
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
prefix = WxCpTpMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "memory", matchIfMissing = true
|
||||
)
|
||||
@RequiredArgsConstructor
|
||||
public class WxCpTpInMemoryTpConfiguration extends AbstractWxCpTpConfiguration {
|
||||
private final WxCpTpMultiProperties wxCpTpMultiProperties;
|
||||
|
||||
@Bean
|
||||
public WxCpTpMultiServices wxCpMultiServices() {
|
||||
return this.wxCpMultiServices(wxCpTpMultiProperties,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
return this.configInMemory();
|
||||
}
|
||||
|
||||
private WxCpTpDefaultConfigImpl configInMemory() {
|
||||
return new WxCpTpDefaultConfigImpl();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
|
||||
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpRedisTemplateConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpTpRedisTemplateConfigImpl;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 自动装配基于 redisTemplate 策略配置
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
prefix = WxCpTpMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "redistemplate"
|
||||
)
|
||||
@RequiredArgsConstructor
|
||||
public class WxCpTpInRedisTemplateTpConfiguration extends AbstractWxCpTpConfiguration {
|
||||
private final WxCpTpMultiProperties wxCpTpMultiProperties;
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
@Bean
|
||||
public WxCpTpMultiServices wxCpMultiServices() {
|
||||
return this.wxCpMultiServices(wxCpTpMultiProperties,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
return this.configRedisTemplate(wxCpTpMultiProperties);
|
||||
}
|
||||
|
||||
private WxCpTpDefaultConfigImpl configRedisTemplate(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
|
||||
return new WxCpTpRedisTemplateConfigImpl(redisTemplate, wxCpTpMultiProperties.getConfigStorage().getKeyPrefix());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.configuration.services;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiProperties;
|
||||
import com.binarywang.spring.starter.wxjava.cp.properties.WxCpTpMultiRedisProperties;
|
||||
import com.binarywang.spring.starter.wxjava.cp.service.WxCpTpMultiServices;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.AbstractWxCpTpInRedisConfigImpl;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpTpRedissonConfigImpl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.config.TransportMode;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 自动装配基于 redisson 策略配置
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(
|
||||
prefix = WxCpTpMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "redisson"
|
||||
)
|
||||
@RequiredArgsConstructor
|
||||
public class WxCpTpInRedissonTpConfiguration extends AbstractWxCpTpConfiguration {
|
||||
private final WxCpTpMultiProperties wxCpTpMultiProperties;
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
@Bean
|
||||
public WxCpTpMultiServices wxCpMultiServices() {
|
||||
return this.wxCpMultiServices(wxCpTpMultiProperties,null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WxCpTpDefaultConfigImpl wxCpTpConfigStorage(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
return this.configRedisson(wxCpTpMultiProperties);
|
||||
}
|
||||
|
||||
private WxCpTpDefaultConfigImpl configRedisson(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
WxCpTpMultiRedisProperties redisProperties = wxCpTpMultiProperties.getConfigStorage().getRedis();
|
||||
RedissonClient redissonClient;
|
||||
if (redisProperties != null && StringUtils.isNotEmpty(redisProperties.getHost())) {
|
||||
redissonClient = getRedissonClient(wxCpTpMultiProperties);
|
||||
} else {
|
||||
redissonClient = applicationContext.getBean(RedissonClient.class);
|
||||
}
|
||||
return new WxCpTpRedissonConfigImpl(redissonClient, wxCpTpMultiProperties.getConfigStorage().getKeyPrefix());
|
||||
}
|
||||
|
||||
private RedissonClient getRedissonClient(WxCpTpMultiProperties wxCpTpMultiProperties) {
|
||||
WxCpTpMultiProperties.ConfigStorage storage = wxCpTpMultiProperties.getConfigStorage();
|
||||
WxCpTpMultiRedisProperties redis = storage.getRedis();
|
||||
|
||||
Config config = new Config();
|
||||
config.useSingleServer()
|
||||
.setAddress("redis://" + redis.getHost() + ":" + redis.getPort())
|
||||
.setDatabase(redis.getDatabase())
|
||||
.setPassword(redis.getPassword());
|
||||
config.setTransportMode(TransportMode.NIO);
|
||||
return Redisson.create(config);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 企业微信多企业接入相关配置属性
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ConfigurationProperties(prefix = WxCpTpMultiProperties.PREFIX)
|
||||
public class WxCpTpMultiProperties implements Serializable {
|
||||
private static final long serialVersionUID = -1569510477055668503L;
|
||||
public static final String PREFIX = "wx.cp.tp";
|
||||
|
||||
private Map<String, WxCpTpSingleProperties> corps = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 配置存储策略,默认内存
|
||||
*/
|
||||
private ConfigStorage configStorage = new ConfigStorage();
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class ConfigStorage implements Serializable {
|
||||
private static final long serialVersionUID = 4815731027000065434L;
|
||||
/**
|
||||
* 存储类型
|
||||
*/
|
||||
private StorageType type = StorageType.memory;
|
||||
|
||||
/**
|
||||
* 指定key前缀
|
||||
*/
|
||||
private String keyPrefix = "wx:cp:tp";
|
||||
|
||||
/**
|
||||
* redis连接配置
|
||||
*/
|
||||
@NestedConfigurationProperty
|
||||
private WxCpTpMultiRedisProperties redis = new WxCpTpMultiRedisProperties();
|
||||
|
||||
/**
|
||||
* http客户端类型.
|
||||
*/
|
||||
private HttpClientType httpClientType = HttpClientType.HTTP_CLIENT;
|
||||
|
||||
/**
|
||||
* http代理主机
|
||||
*/
|
||||
private String httpProxyHost;
|
||||
|
||||
/**
|
||||
* http代理端口
|
||||
*/
|
||||
private Integer httpProxyPort;
|
||||
|
||||
/**
|
||||
* http代理用户名
|
||||
*/
|
||||
private String httpProxyUsername;
|
||||
|
||||
/**
|
||||
* http代理密码
|
||||
*/
|
||||
private String httpProxyPassword;
|
||||
|
||||
/**
|
||||
* http 请求最大重试次数
|
||||
* <pre>
|
||||
* {@link me.chanjar.weixin.cp.api.WxCpService#setMaxRetryTimes(int)}
|
||||
* {@link me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl#setMaxRetryTimes(int)}
|
||||
* </pre>
|
||||
*/
|
||||
private int maxRetryTimes = 5;
|
||||
|
||||
/**
|
||||
* http 请求重试间隔
|
||||
* <pre>
|
||||
* {@link me.chanjar.weixin.cp.api.WxCpService#setRetrySleepMillis(int)}
|
||||
* {@link me.chanjar.weixin.cp.api.impl.BaseWxCpServiceImpl#setRetrySleepMillis(int)}
|
||||
* </pre>
|
||||
*/
|
||||
private int retrySleepMillis = 1000;
|
||||
}
|
||||
|
||||
public enum StorageType {
|
||||
/**
|
||||
* 内存
|
||||
*/
|
||||
memory,
|
||||
/**
|
||||
* jedis
|
||||
*/
|
||||
jedis,
|
||||
/**
|
||||
* redisson
|
||||
*/
|
||||
redisson,
|
||||
/**
|
||||
* redistemplate
|
||||
*/
|
||||
redistemplate
|
||||
}
|
||||
|
||||
public enum HttpClientType {
|
||||
/**
|
||||
* HttpClient
|
||||
*/
|
||||
HTTP_CLIENT,
|
||||
/**
|
||||
* OkHttp
|
||||
*/
|
||||
OK_HTTP,
|
||||
/**
|
||||
* JoddHttp
|
||||
*/
|
||||
JODD_HTTP
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Redis配置.
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class WxCpTpMultiRedisProperties implements Serializable {
|
||||
private static final long serialVersionUID = -5924815351660074401L;
|
||||
|
||||
/**
|
||||
* 主机地址.
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* 端口号.
|
||||
*/
|
||||
private int port = 6379;
|
||||
|
||||
/**
|
||||
* 密码.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 超时.
|
||||
*/
|
||||
private int timeout = 2000;
|
||||
|
||||
/**
|
||||
* 数据库.
|
||||
*/
|
||||
private int database = 0;
|
||||
|
||||
private Integer maxActive;
|
||||
private Integer maxIdle;
|
||||
private Integer maxWaitMillis;
|
||||
private Integer minIdle;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 企业微信企业相关配置属性
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class WxCpTpSingleProperties implements Serializable {
|
||||
private static final long serialVersionUID = -7502823825007859418L;
|
||||
/**
|
||||
* 微信企业号 corpId
|
||||
*/
|
||||
private String corpId;
|
||||
/**
|
||||
* 微信企业号 服务商 providerSecret
|
||||
*/
|
||||
private String providerSecret;
|
||||
/**
|
||||
* 微信企业号应用 token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
private String encodingAESKey;
|
||||
|
||||
/**
|
||||
* 微信企业号 第三方 应用 ID
|
||||
*/
|
||||
private String suiteId;
|
||||
/**
|
||||
* 微信企业号应用
|
||||
*/
|
||||
private String suiteSecret;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.service;
|
||||
|
||||
|
||||
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
|
||||
|
||||
/**
|
||||
* 企业微信 {@link WxCpTpService} 所有实例存放类.
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
public interface WxCpTpMultiServices {
|
||||
/**
|
||||
* 通过租户 Id 获取 WxCpTpService
|
||||
*
|
||||
* @param tenantId 租户 Id
|
||||
* @return WxCpTpService
|
||||
*/
|
||||
WxCpTpService getWxCpTpService(String tenantId);
|
||||
|
||||
void addWxCpTpService(String tenantId, WxCpTpService wxCpService);
|
||||
|
||||
/**
|
||||
* 根据租户 Id,从列表中移除一个 WxCpTpService 实例
|
||||
*
|
||||
* @param tenantId 租户 Id
|
||||
*/
|
||||
void removeWxCpTpService(String tenantId);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.binarywang.spring.starter.wxjava.cp.service;
|
||||
|
||||
|
||||
import me.chanjar.weixin.cp.tp.service.WxCpTpService;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 企业微信 {@link WxCpTpMultiServices} 默认实现
|
||||
*
|
||||
* @author yl
|
||||
* created on 2023/10/16
|
||||
*/
|
||||
public class WxCpTpMultiServicesImpl implements WxCpTpMultiServices {
|
||||
private final Map<String, WxCpTpService> services = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 通过租户 Id 获取 WxCpTpService
|
||||
*
|
||||
* @param tenantId 租户 Id
|
||||
* @return WxCpTpService
|
||||
*/
|
||||
@Override
|
||||
public WxCpTpService getWxCpTpService(String tenantId) {
|
||||
return this.services.get(tenantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据租户 Id,添加一个 WxCpTpService 到列表
|
||||
*
|
||||
* @param tenantId 租户 Id
|
||||
* @param wxCpService WxCpTpService 实例
|
||||
*/
|
||||
@Override
|
||||
public void addWxCpTpService(String tenantId, WxCpTpService wxCpService) {
|
||||
this.services.put(tenantId, wxCpService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeWxCpTpService(String tenantId) {
|
||||
this.services.remove(tenantId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.binarywang.spring.starter.wxjava.cp.autoconfigure.WxCpTpMultiAutoConfiguration
|
||||
@@ -0,0 +1 @@
|
||||
com.binarywang.spring.starter.wxjava.cp.autoconfigure.WxCpTpMultiAutoConfiguration
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.binarywang.spring.starter.wxjava.miniapp.configuration;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInJedisConfiguration;
|
||||
import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInMemoryConfiguration;
|
||||
import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInRedisTemplateConfiguration;
|
||||
import com.binarywang.spring.starter.wxjava.miniapp.configuration.services.WxMaInRedissonConfiguration;
|
||||
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@@ -17,9 +18,10 @@ import org.springframework.context.annotation.Import;
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxMaMultiProperties.class)
|
||||
@Import({
|
||||
WxMaInJedisConfiguration.class,
|
||||
WxMaInMemoryConfiguration.class,
|
||||
WxMaInRedissonConfiguration.class,
|
||||
WxMaInJedisConfiguration.class,
|
||||
WxMaInMemoryConfiguration.class,
|
||||
WxMaInRedissonConfiguration.class,
|
||||
WxMaInRedisTemplateConfiguration.class
|
||||
})
|
||||
public class WxMaMultiServiceConfiguration {
|
||||
}
|
||||
|
||||
@@ -108,12 +108,12 @@ public abstract class AbstractWxMaConfiguration {
|
||||
return wxMaService;
|
||||
}
|
||||
|
||||
private void configApp(WxMaDefaultConfigImpl config, WxMaSingleProperties corpProperties) {
|
||||
String appId = corpProperties.getAppId();
|
||||
String appSecret = corpProperties.getAppSecret();
|
||||
String token = corpProperties.getToken();
|
||||
String aesKey = corpProperties.getAesKey();
|
||||
boolean useStableAccessToken = corpProperties.isUseStableAccessToken();
|
||||
private void configApp(WxMaDefaultConfigImpl config, WxMaSingleProperties properties) {
|
||||
String appId = properties.getAppId();
|
||||
String appSecret = properties.getAppSecret();
|
||||
String token = properties.getToken();
|
||||
String aesKey = properties.getAesKey();
|
||||
boolean useStableAccessToken = properties.isUseStableAccessToken();
|
||||
|
||||
config.setAppid(appId);
|
||||
config.setSecret(appSecret);
|
||||
@@ -123,7 +123,10 @@ public abstract class AbstractWxMaConfiguration {
|
||||
if (StringUtils.isNotBlank(aesKey)) {
|
||||
config.setAesKey(aesKey);
|
||||
}
|
||||
config.setMsgDataFormat(properties.getMsgDataFormat());
|
||||
config.useStableAccessToken(useStableAccessToken);
|
||||
config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
|
||||
config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
|
||||
}
|
||||
|
||||
private void configHttp(WxMaDefaultConfigImpl config, WxMaMultiProperties.ConfigStorage storage) {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.binarywang.spring.starter.wxjava.miniapp.configuration.services;
|
||||
|
||||
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
|
||||
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
|
||||
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaMultiProperties;
|
||||
import com.binarywang.spring.starter.wxjava.miniapp.service.WxMaMultiServices;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 自动装配基于 redisTemplate 策略配置
|
||||
*
|
||||
* @author <a href="mailto:huangbing0730@gmail">hb0730</a> 2025/9/10
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = WxMaMultiProperties.PREFIX + ".config-storage", name = "type", havingValue = "redis_template")
|
||||
@RequiredArgsConstructor
|
||||
public class WxMaInRedisTemplateConfiguration extends AbstractWxMaConfiguration {
|
||||
private final WxMaMultiProperties wxMaMultiProperties;
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
@Bean
|
||||
public WxMaMultiServices wxMaMultiServices() {
|
||||
return this.wxMaMultiServices(wxMaMultiProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WxMaDefaultConfigImpl wxMaConfigStorage(WxMaMultiProperties wxMaMultiProperties) {
|
||||
return this.configRedisTemplate(wxMaMultiProperties);
|
||||
}
|
||||
|
||||
private WxMaDefaultConfigImpl configRedisTemplate(WxMaMultiProperties wxMaMultiProperties) {
|
||||
StringRedisTemplate redisTemplate = applicationContext.getBean(StringRedisTemplate.class);
|
||||
RedisTemplateWxRedisOps wxRedisOps = new RedisTemplateWxRedisOps(redisTemplate);
|
||||
return new WxMaRedisBetterConfigImpl(wxRedisOps, wxMaMultiProperties.getConfigStorage().getKeyPrefix());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,8 +33,25 @@ public class WxMaSingleProperties implements Serializable {
|
||||
*/
|
||||
private String aesKey;
|
||||
|
||||
/**
|
||||
* 消息格式,XML或者JSON.
|
||||
*/
|
||||
private String msgDataFormat;
|
||||
|
||||
/**
|
||||
* 是否使用稳定版 Access Token
|
||||
*/
|
||||
private boolean useStableAccessToken = false;
|
||||
|
||||
/**
|
||||
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
|
||||
* 例如:http://proxy.company.com:8080
|
||||
*/
|
||||
private String apiHostUrl;
|
||||
|
||||
/**
|
||||
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
|
||||
* 例如:http://proxy.company.com:8080/oauth/token
|
||||
*/
|
||||
private String accessTokenUrl;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.binarywang.spring.starter.wxjava.miniapp.config.storage;
|
||||
|
||||
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
|
||||
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
||||
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -10,12 +12,15 @@ import org.apache.commons.lang3.StringUtils;
|
||||
public abstract class AbstractWxMaConfigStorageConfiguration {
|
||||
|
||||
protected WxMaDefaultConfigImpl config(WxMaDefaultConfigImpl config, WxMaProperties properties) {
|
||||
WxMaProperties.ConfigStorage storage = properties.getConfigStorage();
|
||||
config.setAppid(StringUtils.trimToNull(properties.getAppid()));
|
||||
config.setSecret(StringUtils.trimToNull(properties.getSecret()));
|
||||
config.setToken(StringUtils.trimToNull(properties.getToken()));
|
||||
config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
|
||||
config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
|
||||
config.useStableAccessToken(properties.isUseStableAccessToken());
|
||||
config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
|
||||
config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
|
||||
|
||||
WxMaProperties.ConfigStorage configStorageProperties = properties.getConfigStorage();
|
||||
config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
|
||||
@@ -25,6 +30,19 @@ public abstract class AbstractWxMaConfigStorageConfiguration {
|
||||
config.setHttpProxyPort(configStorageProperties.getHttpProxyPort());
|
||||
}
|
||||
|
||||
// 设置自定义的HttpClient超时配置
|
||||
ApacheHttpClientBuilder clientBuilder = config.getApacheHttpClientBuilder();
|
||||
if (clientBuilder == null) {
|
||||
clientBuilder = DefaultApacheHttpClientBuilder.get();
|
||||
}
|
||||
if (clientBuilder instanceof DefaultApacheHttpClientBuilder) {
|
||||
DefaultApacheHttpClientBuilder defaultBuilder = (DefaultApacheHttpClientBuilder) clientBuilder;
|
||||
defaultBuilder.setConnectionTimeout(storage.getConnectionTimeout());
|
||||
defaultBuilder.setSoTimeout(storage.getSoTimeout());
|
||||
defaultBuilder.setConnectionRequestTimeout(storage.getConnectionRequestTimeout());
|
||||
config.setApacheHttpClientBuilder(defaultBuilder);
|
||||
}
|
||||
|
||||
int maxRetryTimes = configStorageProperties.getMaxRetryTimes();
|
||||
if (configStorageProperties.getMaxRetryTimes() < 0) {
|
||||
maxRetryTimes = 0;
|
||||
|
||||
@@ -49,6 +49,18 @@ public class WxMaProperties {
|
||||
*/
|
||||
private boolean useStableAccessToken = false;
|
||||
|
||||
/**
|
||||
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
|
||||
* 例如:http://proxy.company.com:8080
|
||||
*/
|
||||
private String apiHostUrl;
|
||||
|
||||
/**
|
||||
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
|
||||
* 例如:http://proxy.company.com:8080/oauth/token
|
||||
*/
|
||||
private String accessTokenUrl;
|
||||
|
||||
/**
|
||||
* 存储策略
|
||||
*/
|
||||
@@ -112,6 +124,21 @@ public class WxMaProperties {
|
||||
* </pre>
|
||||
*/
|
||||
private int maxRetryTimes = 5;
|
||||
|
||||
/**
|
||||
* 连接超时时间,单位毫秒
|
||||
*/
|
||||
private int connectionTimeout = 5000;
|
||||
|
||||
/**
|
||||
* 读数据超时时间,即socketTimeout,单位毫秒
|
||||
*/
|
||||
private int soTimeout = 5000;
|
||||
|
||||
/**
|
||||
* 从连接池获取链接的超时时间,单位毫秒
|
||||
*/
|
||||
private int connectionRequestTimeout = 5000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -7,10 +7,7 @@ import com.binarywang.spring.starter.wxjava.mp.service.WxMpMultiServicesImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceHttpClientImpl;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceJoddHttpImpl;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceOkHttpImpl;
|
||||
import me.chanjar.weixin.mp.api.impl.*;
|
||||
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
|
||||
import me.chanjar.weixin.mp.config.WxMpHostConfig;
|
||||
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
|
||||
@@ -91,6 +88,9 @@ public abstract class AbstractWxMpConfiguration {
|
||||
case HTTP_CLIENT:
|
||||
wxMpService = new WxMpServiceHttpClientImpl();
|
||||
break;
|
||||
case HTTP_COMPONENTS:
|
||||
wxMpService = new WxMpServiceHttpComponentsImpl();
|
||||
break;
|
||||
default:
|
||||
wxMpService = new WxMpServiceImpl();
|
||||
break;
|
||||
|
||||
@@ -142,6 +142,10 @@ public class WxMpMultiProperties implements Serializable {
|
||||
* HttpClient
|
||||
*/
|
||||
HTTP_CLIENT,
|
||||
/**
|
||||
* HttpComponents
|
||||
*/
|
||||
HTTP_COMPONENTS,
|
||||
/**
|
||||
* OkHttp
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -102,6 +102,21 @@ public class WxMpProperties {
|
||||
*/
|
||||
private String httpProxyPassword;
|
||||
|
||||
/**
|
||||
* 连接超时时间,单位毫秒
|
||||
*/
|
||||
private int connectionTimeout = 5000;
|
||||
|
||||
/**
|
||||
* 读数据超时时间,即socketTimeout,单位毫秒
|
||||
*/
|
||||
private int soTimeout = 5000;
|
||||
|
||||
/**
|
||||
* 从连接池获取链接的超时时间,单位毫秒
|
||||
*/
|
||||
private int connectionRequestTimeout = 5000;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ public class WxOpenServiceAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public WxOpenMessageRouter wxOpenMessageRouter(WxOpenService wxOpenService) {
|
||||
return new WxOpenMessageRouter(wxOpenService);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.binarywang.spring.starter.wxjava.open.config.storage;
|
||||
|
||||
import com.binarywang.spring.starter.wxjava.open.properties.WxOpenProperties;
|
||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
||||
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
|
||||
import me.chanjar.weixin.open.api.impl.WxOpenInMemoryConfigStorage;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* @author yl
|
||||
@@ -28,6 +31,24 @@ public abstract class AbstractWxOpenConfigStorageConfiguration {
|
||||
}
|
||||
config.setRetrySleepMillis(retrySleepMillis);
|
||||
config.setMaxRetryTimes(maxRetryTimes);
|
||||
|
||||
// 设置URL配置
|
||||
config.setApiHostUrl(StringUtils.trimToNull(properties.getApiHostUrl()));
|
||||
config.setAccessTokenUrl(StringUtils.trimToNull(properties.getAccessTokenUrl()));
|
||||
|
||||
// 设置自定义的HttpClient超时配置
|
||||
ApacheHttpClientBuilder clientBuilder = config.getApacheHttpClientBuilder();
|
||||
if (clientBuilder == null) {
|
||||
clientBuilder = DefaultApacheHttpClientBuilder.get();
|
||||
}
|
||||
if (clientBuilder instanceof DefaultApacheHttpClientBuilder) {
|
||||
DefaultApacheHttpClientBuilder defaultBuilder = (DefaultApacheHttpClientBuilder) clientBuilder;
|
||||
defaultBuilder.setConnectionTimeout(storage.getConnectionTimeout());
|
||||
defaultBuilder.setSoTimeout(storage.getSoTimeout());
|
||||
defaultBuilder.setConnectionRequestTimeout(storage.getConnectionRequestTimeout());
|
||||
config.setApacheHttpClientBuilder(defaultBuilder);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,18 @@ public class WxOpenProperties {
|
||||
*/
|
||||
private String aesKey;
|
||||
|
||||
/**
|
||||
* 自定义API主机地址,用于替换默认的 https://api.weixin.qq.com
|
||||
* 例如:http://proxy.company.com:8080
|
||||
*/
|
||||
private String apiHostUrl;
|
||||
|
||||
/**
|
||||
* 自定义获取AccessToken地址,用于向自定义统一服务获取AccessToken
|
||||
* 例如:http://proxy.company.com:8080/oauth/token
|
||||
*/
|
||||
private String accessTokenUrl;
|
||||
|
||||
/**
|
||||
* 存储策略.
|
||||
*/
|
||||
@@ -108,6 +120,21 @@ public class WxOpenProperties {
|
||||
*/
|
||||
private int maxRetryTimes = 5;
|
||||
|
||||
/**
|
||||
* 连接超时时间,单位毫秒
|
||||
*/
|
||||
private int connectionTimeout = 5000;
|
||||
|
||||
/**
|
||||
* 读数据超时时间,即socketTimeout,单位毫秒
|
||||
*/
|
||||
private int soTimeout = 5000;
|
||||
|
||||
/**
|
||||
* 从连接池获取链接的超时时间,单位毫秒
|
||||
*/
|
||||
private int connectionRequestTimeout = 5000;
|
||||
|
||||
}
|
||||
|
||||
public enum StorageType {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.4.B</version>
|
||||
<version>4.7.9.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -131,5 +131,5 @@ public interface BaseWxChannelService extends WxService {
|
||||
*
|
||||
* @return . request http
|
||||
*/
|
||||
RequestHttp getRequestHttp();
|
||||
RequestHttp<?, ?> getRequestHttp();
|
||||
}
|
||||
|
||||
@@ -2,10 +2,8 @@ package me.chanjar.weixin.channel.api;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import me.chanjar.weixin.channel.bean.after.AfterSaleInfoResponse;
|
||||
import me.chanjar.weixin.channel.bean.after.AfterSaleListResponse;
|
||||
import me.chanjar.weixin.channel.bean.after.AfterSaleReasonResponse;
|
||||
import me.chanjar.weixin.channel.bean.after.AfterSaleRejectReasonResponse;
|
||||
|
||||
import me.chanjar.weixin.channel.bean.after.*;
|
||||
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
|
||||
import me.chanjar.weixin.channel.bean.complaint.ComplaintOrderResponse;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
@@ -26,10 +24,22 @@ public interface WxChannelAfterSaleService {
|
||||
* @return 售后单列表
|
||||
*
|
||||
* @throws WxErrorException 异常
|
||||
* @deprecated 使用 {@link WxChannelAfterSaleService#listIds(AfterSaleListParam)}
|
||||
*/
|
||||
@Deprecated
|
||||
AfterSaleListResponse listIds(Long beginCreateTime, Long endCreateTime, String nextKey)
|
||||
throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取售后单列表
|
||||
*
|
||||
* @param param 参数
|
||||
* @return 售后单列表
|
||||
*
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
AfterSaleListResponse listIds(AfterSaleListParam param) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取售后单详情
|
||||
*
|
||||
@@ -136,4 +146,41 @@ public interface WxChannelAfterSaleService {
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
AfterSaleRejectReasonResponse getRejectReason() throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 换货发货
|
||||
* 文档地址:https://developers.weixin.qq.com/doc/store/shop/API/channels-shop-aftersale/api_acceptexchangereship.html
|
||||
*
|
||||
* @param afterSaleOrderId 售后单号
|
||||
* @param waybillId 快递单号
|
||||
* @param deliveryId 快递公司id
|
||||
* @return BaseResponse
|
||||
*
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
WxChannelBaseResponse acceptExchangeReship(String afterSaleOrderId, String waybillId, String deliveryId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 换货拒绝发货
|
||||
* 文档地址:https://developers.weixin.qq.com/doc/store/shop/API/channels-shop-aftersale/api_rejectexchangereship.html
|
||||
*
|
||||
* @param afterSaleOrderId 售后单号
|
||||
* @param rejectReason 拒绝原因具体描述 ,可使用默认描述,也可以自定义描述
|
||||
* @param rejectReasonType 拒绝原因枚举值
|
||||
* @param rejectCertificates 退款凭证,可使用图片上传接口获取media_id(数据类型填0)
|
||||
* @return BaseResponse
|
||||
*
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
WxChannelBaseResponse rejectExchangeReship(String afterSaleOrderId, String rejectReason, Integer rejectReasonType, List<String> rejectCertificates) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 商家协商
|
||||
* 文档地址:https://developers.weixin.qq.com/doc/store/shop/API/channels-shop-aftersale/api_merchantupdateaftersale.html
|
||||
* @param param 参数
|
||||
* @return BaseResponse
|
||||
*
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
WxChannelBaseResponse merchantUpdateAfterSale(AfterSaleMerchantUpdateParam param) throws WxErrorException;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,17 @@ public interface WxChannelOrderService {
|
||||
*/
|
||||
OrderInfoResponse getOrder(String orderId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取订单详情
|
||||
*
|
||||
* @param orderId 订单id
|
||||
* @param encodeSensitiveInfo 是否编码敏感信息
|
||||
* @return 订单详情
|
||||
*
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
OrderInfoResponse getOrder(String orderId, Boolean encodeSensitiveInfo) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取订单列表
|
||||
*
|
||||
@@ -128,7 +139,7 @@ public interface WxChannelOrderService {
|
||||
WxChannelBaseResponse closeOrder(String orderId);
|
||||
|
||||
/**
|
||||
* 获取快递公司列表
|
||||
* 获取快递公司列表-旧
|
||||
*
|
||||
* @return 快递公司列表
|
||||
*
|
||||
@@ -136,6 +147,16 @@ public interface WxChannelOrderService {
|
||||
*/
|
||||
DeliveryCompanyResponse listDeliveryCompany() throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取快递公司列表
|
||||
*
|
||||
* @param ewaybillOnly 是否仅返回支持电子面单功能的快递公司
|
||||
* @return 快递公司列表
|
||||
*
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
DeliveryCompanyResponse listDeliveryCompany(Boolean ewaybillOnly) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 订单发货
|
||||
*
|
||||
|
||||
@@ -15,43 +15,84 @@ public interface WxLeaguePromoterService {
|
||||
/**
|
||||
* 新增达人
|
||||
*
|
||||
* @param finderId 视频号finder_id
|
||||
* @param finderId 视频号finder_id,待废除
|
||||
* @return 结果
|
||||
* @deprecated 使用 {@link #addPromoterV2(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
WxChannelBaseResponse addPromoter(String finderId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 编辑达人
|
||||
*
|
||||
* @param finderId 视频号finder_id
|
||||
* @param finderId 视频号finder_id,待废除
|
||||
* @param type 操作 1取消邀请 2结束合作
|
||||
* @return 结果
|
||||
* @deprecated 使用 {@link #updatePromoterV2(String, int)}
|
||||
*/
|
||||
@Deprecated
|
||||
WxChannelBaseResponse updatePromoter(String finderId, int type) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 删除达人
|
||||
*
|
||||
* @param finderId 视频号finder_id
|
||||
* @param finderId 视频号finder_id,待废除
|
||||
* @return 结果
|
||||
* @deprecated 使用 {@link #deletePromoterV2(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
WxChannelBaseResponse deletePromoter(String finderId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取达人详情信息
|
||||
*
|
||||
* @param finderId 视频号finder_id
|
||||
* @param finderId 视频号finder_id,待废除
|
||||
* @return 结果
|
||||
* @deprecated 使用 {@link #getPromoterInfoV2(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
PromoterInfoResponse getPromoterInfo(String finderId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取达人列表
|
||||
*
|
||||
* @param pageIndex 页面下标,下标从1开始,默认为1
|
||||
* @param pageSize 单页达人数(不超过200)
|
||||
* @param status 拉取该状态下的达人列表
|
||||
* @return 结果
|
||||
*/
|
||||
PromoterListResponse listPromoter(Integer pageIndex, Integer pageSize, Integer status) throws WxErrorException;
|
||||
/**
|
||||
* 新增达人
|
||||
*
|
||||
* @param promoterId 达人带货id
|
||||
* @return 结果
|
||||
*/
|
||||
WxChannelBaseResponse addPromoterV2(String promoterId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 编辑达人
|
||||
*
|
||||
* @param promoterId 达人带货id
|
||||
* @param type 操作 1取消邀请 2结束合作
|
||||
* @return 结果
|
||||
*/
|
||||
WxChannelBaseResponse updatePromoterV2(String promoterId, int type) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 删除达人
|
||||
*
|
||||
* @param promoterId 达人带货id
|
||||
* @return 结果
|
||||
*/
|
||||
WxChannelBaseResponse deletePromoterV2(String promoterId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取达人详情信息
|
||||
*
|
||||
* @param promoterId 达人带货id
|
||||
* @return 结果
|
||||
*/
|
||||
PromoterInfoResponse getPromoterInfoV2(String promoterId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取达人列表
|
||||
*
|
||||
* @param pageIndex 页面下标,下标从1开始,默认为1
|
||||
* @param pageSize 单页达人数(不超过200)
|
||||
* @param status 拉取该状态下的达人列表
|
||||
* @return 结果
|
||||
*/
|
||||
PromoterListResponse listPromoter(Integer pageIndex, Integer pageSize, Integer status) throws WxErrorException;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
|
||||
private int maxRetryTimes = 5;
|
||||
|
||||
@Override
|
||||
public RequestHttp getRequestHttp() {
|
||||
public RequestHttp<H, P> getRequestHttp() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
|
||||
try {
|
||||
return SHA1.gen(this.getConfig().getToken(), timestamp, nonce).equals(signature);
|
||||
} catch (Exception e) {
|
||||
log.error("Checking signature failed, and the reason is :" + e.getMessage());
|
||||
log.error("Checking signature failed, and the reason is :{}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -276,7 +276,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
protected String extractAccessToken(String resultContent) throws WxErrorException {
|
||||
log.debug("access-token response: " + resultContent);
|
||||
log.debug("access-token response: {}", resultContent);
|
||||
WxChannelConfig config = this.getConfig();
|
||||
WxError error = WxError.fromJson(resultContent, WxType.Channel);
|
||||
if (error.getErrorCode() != 0) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Assist
|
||||
public class WxAssistantServiceImpl implements WxAssistantService {
|
||||
|
||||
/** 微信商店服务 */
|
||||
private final BaseWxChannelServiceImpl shopService;
|
||||
private final BaseWxChannelServiceImpl<?, ?> shopService;
|
||||
@Override
|
||||
public WxChannelBaseResponse addWindowProduct(AddWindowProductRequest req) throws WxErrorException {
|
||||
String resJson = shopService.post(ADD_WINDOW_PRODUCT_URL, "{}");
|
||||
|
||||
@@ -29,9 +29,9 @@ import me.chanjar.weixin.common.error.WxErrorException;
|
||||
public class WxChannelAddressServiceImpl implements WxChannelAddressService {
|
||||
|
||||
/** 微信商店服务 */
|
||||
private final BaseWxChannelServiceImpl shopService;
|
||||
private final BaseWxChannelServiceImpl<?, ?> shopService;
|
||||
|
||||
public WxChannelAddressServiceImpl(BaseWxChannelServiceImpl shopService) {
|
||||
public WxChannelAddressServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
|
||||
this.shopService = shopService;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,17 +22,25 @@ import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Compla
|
||||
@Slf4j
|
||||
public class WxChannelAfterSaleServiceImpl implements WxChannelAfterSaleService {
|
||||
|
||||
/** 微信商店服务 */
|
||||
private final BaseWxChannelServiceImpl shopService;
|
||||
/**
|
||||
* 微信商店服务
|
||||
*/
|
||||
private final BaseWxChannelServiceImpl<?, ?> shopService;
|
||||
|
||||
public WxChannelAfterSaleServiceImpl(BaseWxChannelServiceImpl shopService) {
|
||||
public WxChannelAfterSaleServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
|
||||
this.shopService = shopService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AfterSaleListResponse listIds(Long beginCreateTime, Long endCreateTime, String nextKey)
|
||||
throws WxErrorException {
|
||||
AfterSaleListParam param = new AfterSaleListParam(beginCreateTime, endCreateTime, nextKey);
|
||||
AfterSaleListParam param = new AfterSaleListParam(beginCreateTime, endCreateTime, null, null, nextKey);
|
||||
String resJson = shopService.post(AFTER_SALE_LIST_URL, param);
|
||||
return ResponseUtils.decode(resJson, AfterSaleListResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AfterSaleListResponse listIds(AfterSaleListParam param) throws WxErrorException {
|
||||
String resJson = shopService.post(AFTER_SALE_LIST_URL, param);
|
||||
return ResponseUtils.decode(resJson, AfterSaleListResponse.class);
|
||||
}
|
||||
@@ -101,4 +109,25 @@ public class WxChannelAfterSaleServiceImpl implements WxChannelAfterSaleService
|
||||
String resJson = shopService.post(AFTER_SALE_REJECT_REASON_GET_URL, "{}");
|
||||
return ResponseUtils.decode(resJson, AfterSaleRejectReasonResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxChannelBaseResponse acceptExchangeReship(String afterSaleOrderId, String waybillId, String deliveryId) throws WxErrorException {
|
||||
AfterSaleAcceptExchangeReshipParam param = new AfterSaleAcceptExchangeReshipParam(afterSaleOrderId, waybillId, deliveryId);
|
||||
String resJson = shopService.post(AFTER_SALE_ACCEPT_EXCHANGE_RESHIP_URL, param);
|
||||
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxChannelBaseResponse rejectExchangeReship(String afterSaleOrderId, String rejectReason, Integer rejectReasonType, List<String> rejectCertificates) throws WxErrorException {
|
||||
AfterSaleRejectExchangeReshipParam param = new AfterSaleRejectExchangeReshipParam(afterSaleOrderId, rejectReason, rejectReasonType, rejectCertificates);
|
||||
String resJson = shopService.post(AFTER_SALE_REJECT_EXCHANGE_RESHIP_URL, param);
|
||||
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxChannelBaseResponse merchantUpdateAfterSale(AfterSaleMerchantUpdateParam param) throws WxErrorException {
|
||||
String resJson = shopService.post(AFTER_SALE_MERCHANT_UPDATE_URL, param);
|
||||
return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 + "}";
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user